/*===========================================================================* * driver_init * *===========================================================================*/ void driver_init(void) { /* Initialize the driver layer. */ int r; memset(driver, 0, sizeof(driver)); /* Endpoints unknown. */ driver[DRIVER_MAIN].endpt = NONE; driver[DRIVER_BACKUP].endpt = NONE; /* Get disk driver's and this proc's endpoint. */ driver[DRIVER_MAIN].label = MAIN_LABEL; driver[DRIVER_MAIN].minor = MAIN_MINOR; /* No up received yet but expected when the driver starts. */ driver[DRIVER_MAIN].up_event = UP_EXPECTED; driver[DRIVER_BACKUP].up_event = UP_EXPECTED; r = ds_retrieve_label_endpt(driver[DRIVER_MAIN].label, &driver[DRIVER_MAIN].endpt); if (r != OK) { printf("Filter: failed to get main disk driver's endpoint: " "%d\n", r); bad_driver(DRIVER_MAIN, BD_DEAD, EFAULT); check_driver(DRIVER_MAIN); } else if (driver_open(DRIVER_MAIN) != OK) { panic("unhandled driver_open failure"); } if(USE_MIRROR) { driver[DRIVER_BACKUP].label = BACKUP_LABEL; driver[DRIVER_BACKUP].minor = BACKUP_MINOR; if(!strcmp(driver[DRIVER_MAIN].label, driver[DRIVER_BACKUP].label)) { panic("same driver: not tested"); } r = ds_retrieve_label_endpt(driver[DRIVER_BACKUP].label, &driver[DRIVER_BACKUP].endpt); if (r != OK) { printf("Filter: failed to get backup disk driver's " "endpoint: %d\n", r); bad_driver(DRIVER_BACKUP, BD_DEAD, EFAULT); check_driver(DRIVER_BACKUP); } else if (driver_open(DRIVER_BACKUP) != OK) { panic("unhandled driver_open failure"); } } }
/***************************************************************************** * usb_init * ****************************************************************************/ int usb_init(char *name) { int res; message msg; /* get the endpoint of the HCD */ res = ds_retrieve_label_endpt("usbd", &hcd_ep); if (res != 0) { panic("usb_init: ds_retrieve_label_endpt failed for 'usb': %d", res); } msg.m_type = USB_RQ_INIT; strncpy(msg.USB_RB_INIT_NAME, name, M3_LONG_STRING); res = sendrec(hcd_ep, &msg); if (res != 0) { panic("usb_init: can't talk to USB: %d", res); } if (msg.m_type != USB_REPLY) { panic("usb_init: bad reply from USB: %d", msg.m_type); } if (msg.USB_RESULT != 0 ) { panic("usb_init: init failed: %ld", msg.USB_RESULT); } return 0; }
/*===========================================================================* * new_driver_ep * *===========================================================================*/ static int new_driver_ep(int which) { /* See if a new driver instance has already been started for the given * driver, by retrieving its entry from DS. */ int r; endpoint_t endpt; r = ds_retrieve_label_endpt(driver[which].label, &endpt); if (r != OK) { printf("Filter: DS query for %s failed\n", driver[which].label); return 0; } if (endpt == driver[which].endpt) { #if DEBUG printf("Filter: same endpoint for %s\n", driver[which].label); #endif return 0; } #if DEBUG printf("Filter: new enpdoint for %s: %d -> %d\n", driver[which].label, driver[which].endpt, endpt); #endif driver[which].endpt = endpt; return 1; }
/*===========================================================================* * do_reboot * *===========================================================================*/ int do_reboot() { message m; /* Check permission to abort the system. */ if (mp->mp_effuid != SUPER_USER) return(EPERM); /* See how the system should be aborted. */ abort_flag = m_in.m_lc_pm_reboot.how; /* notify readclock (some arm systems power off via RTC alarms) */ if (abort_flag & RB_POWERDOWN) { endpoint_t readclock_ep; if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) { message m; /* no params to set, nothing we can do if it fails */ _taskcall(readclock_ep, RTCDEV_PWR_OFF, &m); } } /* Order matters here. When VFS is told to reboot, it exits all its * processes, and then would be confused if they're exited again by * SIGKILL. So first kill, then reboot. */ check_sig(-1, SIGKILL, FALSE /* ksig*/); /* kill all users except init */ sys_stop(INIT_PROC_NR); /* stop init, but keep it around */ /* Tell VFS to reboot */ memset(&m, 0, sizeof(m)); m.m_type = VFS_PM_REBOOT; tell_vfs(&mproc[VFS_PROC_NR], &m); return(SUSPEND); /* don't reply to caller */ }
/*===========================================================================* * do_mapdriver * *===========================================================================*/ int do_mapdriver(void) { /* Create a device->driver mapping. RS will tell us which major is driven by * this driver, what type of device it is (regular, TTY, asynchronous, clone, * etc), and its label. This label is registered with DS, and allows us to * retrieve the driver's endpoint. */ int r, slot; devmajor_t major; endpoint_t endpoint; vir_bytes label_vir; size_t label_len; char label[LABEL_MAX]; struct fproc *rfp; /* Only RS can map drivers. */ if (who_e != RS_PROC_NR) return(EPERM); label_vir = job_m_in.m_lsys_vfs_mapdriver.label; label_len = job_m_in.m_lsys_vfs_mapdriver.labellen; major = job_m_in.m_lsys_vfs_mapdriver.major; /* Get the label */ if (label_len > sizeof(label)) { /* Can we store this label? */ printf("VFS: do_mapdriver: label too long\n"); return(EINVAL); } r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len, CP_FLAG_TRY); if (r != OK) { printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r); return(EINVAL); } if (label[label_len-1] != '\0') { printf("VFS: do_mapdriver: label not null-terminated\n"); return(EINVAL); } /* Now we know how the driver is called, fetch its endpoint */ r = ds_retrieve_label_endpt(label, &endpoint); if (r != OK) { printf("VFS: do_mapdriver: label '%s' unknown\n", label); return(EINVAL); } /* Process is a service */ if (isokendpt(endpoint, &slot) != OK) { printf("VFS: can't map driver to unknown endpoint %d\n", endpoint); return(EINVAL); } rfp = &fproc[slot]; rfp->fp_flags |= FP_SRV_PROC; /* Try to update device mapping. */ return map_driver(label, major, endpoint); }
/*===========================================================================* * do_mount * *===========================================================================*/ PUBLIC int do_mount() { /* Perform the mount(name, mfile, mount_flags) system call. */ endpoint_t fs_e; int r, slot, rdonly, nodev; char fullpath[PATH_MAX]; char mount_label[LABEL_MAX]; dev_t dev; /* Only the super-user may do MOUNT. */ if (!super_user) return(EPERM); /* FS process' endpoint number */ if (m_in.mount_flags & MS_LABEL16) { /* Get the label from the caller, and ask DS for the endpoint. */ r = sys_datacopy(who_e, (vir_bytes) m_in.fs_label, SELF, (vir_bytes) mount_label, (phys_bytes) sizeof(mount_label)); if (r != OK) return(r); mount_label[sizeof(mount_label)-1] = 0; r = ds_retrieve_label_endpt(mount_label, &fs_e); if (r != OK) return(r); } else { /* Legacy support: get the endpoint from the request itself. */ fs_e = (endpoint_t) m_in.fs_label; mount_label[0] = 0; } /* Sanity check on process number. */ if (isokendpt(fs_e, &slot) != OK) return(EINVAL); /* Should the file system be mounted read-only? */ rdonly = (m_in.mount_flags & MS_RDONLY); /* A null string for block special device means don't use a device at all. */ nodev = (m_in.name1_length == 0); if (!nodev) { /* If 'name' is not for a block special file, return error. */ if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) return(err_code); if ((dev = name_to_dev(FALSE /*allow_mountpt*/, fullpath)) == NO_DEV) return(err_code); } else { /* Find a free pseudo-device as substitute for an actual device. */ if ((dev = find_free_nonedev()) == NO_DEV) return(err_code); } /* Fetch the name of the mountpoint */ if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) return(err_code); /* Do the actual job */ return mount_fs(dev, fullpath, fs_e, rdonly, mount_label); }
/*===========================================================================* * fs_readsuper * *===========================================================================*/ PUBLIC int fs_readsuper() { cp_grant_id_t label_gid; size_t label_len; int r = OK; endpoint_t driver_e; int readonly; fs_dev = fs_m_in.REQ_DEV; label_gid = fs_m_in.REQ_GRANT; label_len = fs_m_in.REQ_PATH_LEN; readonly = 1; /* Always mount devices read only. */ if (label_len > sizeof(fs_dev_label)) return(EINVAL); r = sys_safecopyfrom(fs_m_in.m_source, label_gid, 0, (vir_bytes)fs_dev_label, label_len, D); if (r != OK) { printf("ISOFS %s:%d safecopyfrom failed: %d\n", __FILE__, __LINE__, r); return(EINVAL); } r = ds_retrieve_label_endpt(fs_dev_label, &driver_e); if (r != OK) { printf("ISOFS %s:%d ds_retrieve_label_endpt failed for '%s': %d\n", __FILE__, __LINE__, fs_dev_label, r); return(EINVAL); } /* Map the driver endpoint for this major */ driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e = driver_e; /* Open the device the file system lives on */ if (dev_open(driver_e, fs_dev, driver_e, readonly ? R_BIT : (R_BIT|W_BIT)) != OK) { return(EINVAL); } /* Read the superblock */ r = read_vds(&v_pri, fs_dev); if (r != OK) return(r); /* Return some root inode properties */ fs_m_out.RES_INODE_NR = ID_DIR_RECORD(v_pri.dir_rec_root); fs_m_out.RES_MODE = v_pri.dir_rec_root->d_mode; fs_m_out.RES_FILE_SIZE_LO = v_pri.dir_rec_root->d_file_size; fs_m_out.RES_UID = SYS_UID; /* Always root */ fs_m_out.RES_GID = SYS_GID; /* operator */ fs_m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */ return(r); }
/*===========================================================================* * do_mapdriver * *===========================================================================*/ PUBLIC int do_mapdriver() { int r, flags, major; endpoint_t endpoint; vir_bytes label_vir; size_t label_len; char label[LABEL_MAX]; /* Only RS can map drivers. */ if (who_e != RS_PROC_NR) { printf("vfs: unauthorized call of do_mapdriver by proc %d\n", who_e); return(EPERM); } /* Get the label */ label_vir= (vir_bytes)m_in.md_label; label_len= m_in.md_label_len; if (label_len+1 > sizeof(label)) { printf("vfs:do_mapdriver: label too long\n"); return EINVAL; } r= sys_vircopy(who_e, D, label_vir, SELF, D, (vir_bytes)label, label_len); if (r != OK) { printf("vfs:do_mapdriver: sys_vircopy failed: %d\n", r); return EINVAL; } label[label_len]= '\0'; r= ds_retrieve_label_endpt(label, &endpoint); if (r != OK) { printf("vfs:do_mapdriver: ds doesn't know '%s'\n", label); return EINVAL; } /* Try to update device mapping. */ major= m_in.md_major; flags= m_in.md_flags; r= map_driver(label, major, endpoint, m_in.md_style, flags); return(r); }
endpoint_t bdev_driver_update(dev_t dev) { /* Update the endpoint of a driver. The caller of this function already knows * that the current endpoint may no longer be valid, and must be updated. * Return the new endpoint upon success, and NONE otherwise. */ endpoint_t endpt; int r, major, nr_tries; major = major(dev); assert(major >= 0 && major < NR_DEVICES); assert(driver_tab[major].label[0] != '\0'); /* Repeatedly retrieve the endpoint for the driver label, and see if it is a * different, valid endpoint. If retrieval fails at first, we have to wait. * We use polling, as opposed to a DS subscription, for a number of reasons: * 1) DS supports only one subscription per process, and our main program may * already have a subscription; * 2) if we block on receiving a notification from DS, we cannot impose an * upper bound on the retry time; * 3) temporarily subscribing and then unsubscribing may cause leftover DS * notifications, which the main program would then have to deal with. * As of writing, unsubscribing from DS is not possible at all, anyway. * * In the normal case, the driver's label/endpoint mapping entry disappears * completely for a short moment, before being replaced with the new mapping. * Hence, failure to retrieve the entry at all does not constitute permanent * failure. In fact, there is no way to determine reliably that a driver has * failed permanently in the current approach. For this we simply rely on the * retry limit. */ for (nr_tries = 0; nr_tries < DS_NR_TRIES; nr_tries++) { r = ds_retrieve_label_endpt(driver_tab[major].label, &endpt); if (r == OK && endpt != NONE && endpt != driver_tab[major].endpt) { driver_tab[major].endpt = endpt; return endpt; } if (nr_tries < DS_NR_TRIES - 1) micro_delay(DS_DELAY); } driver_tab[major].endpt = NONE; return NONE; }
/*===========================================================================* * pci_init * *===========================================================================*/ PUBLIC void pci_init(void) { int r; message m; r= ds_retrieve_label_endpt("pci", &pci_procnr); if (r != 0) panic("pci_init: unable to obtain label for 'pci': %d", r); m.m_type= BUSC_PCI_INIT; r= sendrec(pci_procnr, &m); if (r != 0) panic("pci_init: can't talk to PCI: %d", r); if (m.m_type != 0) panic("pci_init: got bad reply from PCI: %d", m.m_type); }
/* * Perform synchronous communication with PTYFS, if PTYFS is actually running. * This function is expected to return only once PTYFS has acknowledged * processing the request, in order to avoid race conditions between PTYFS and * userland. The function must always fail when PTYFS is not available for any * reason. Return OK on success, or an IPC-level error on failure. */ static int ptyfs_sendrec(message * m_ptr) { endpoint_t endpt; /* * New pseudoterminals are created sufficiently rarely that we need not * optimize this by for example caching the PTYFS endpoint, especially * since caching brings along new issues, such as having to reissue the * request if the cached endpoint turns out to be outdated (e.g., when * ptyfs is unmounted and remounted for whatever reason). */ if (ds_retrieve_label_endpt("ptyfs", &endpt) != OK) return EDEADSRCDST; /* ptyfs is not available */ return ipc_sendrec(endpt, m_ptr); }
/*===========================================================================* * do_mapdriver * *===========================================================================*/ int do_mapdriver() { /* Create a device->driver mapping. RS will tell us which major is driven by * this driver, what type of device it is (regular, TTY, asynchronous, clone, * etc), and its label. This label is registered with DS, and allows us to * retrieve the driver's endpoint. */ int r, flags, major, style; endpoint_t endpoint; vir_bytes label_vir; size_t label_len; char label[LABEL_MAX]; /* Only RS can map drivers. */ if (who_e != RS_PROC_NR) return(EPERM); label_vir = (vir_bytes) job_m_in.md_label; label_len = (size_t) job_m_in.md_label_len; major = job_m_in.md_major; flags = job_m_in.md_flags; style = job_m_in.md_style; /* Get the label */ if (label_len+1 > sizeof(label)) { /* Can we store this label? */ printf("VFS: do_mapdriver: label too long\n"); return(EINVAL); } r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len); if (r != OK) { printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r); return(EINVAL); } label[label_len] = '\0'; /* Terminate label */ /* Now we know how the driver is called, fetch its endpoint */ r = ds_retrieve_label_endpt(label, &endpoint); if (r != OK) { printf("VFS: do_mapdriver: label '%s' unknown\n", label); return(EINVAL); } /* Try to update device mapping. */ return map_driver(label, major, endpoint, style, flags); }
/*===========================================================================* * test_label * *===========================================================================*/ void test_label(void) { int r; char label[DS_MAX_KEYLEN]; endpoint_t endpoint; /* Retrieve own label and endpoint. */ r = ds_retrieve_label_name(label, getprocnr()); assert(r == OK); r = ds_retrieve_label_endpt(label, &endpoint); assert(r == OK && endpoint == getprocnr()); /* Publish and delete. */ r = ds_publish_label(label, endpoint, 0); assert(r == EPERM); r = ds_delete_label(label); assert(r == EPERM); printf("DSTEST: LABEL test successful!\n"); }
/*===========================================================================* * sef_cb_init_fresh * *===========================================================================*/ static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) { clock_t uptime; int r; /* Parse the given parameters. */ if (env_argc > 1) optset_parse(optset_table, env_argv[1]); if (driver_label[0] == '\0') panic("no driver label given"); if (ds_retrieve_label_endpt(driver_label, &driver_endpt)) panic("unable to resolve driver label"); if (driver_minor > 255) panic("no or invalid driver minor given"); #if DEBUG printf("FBD: driver label '%s' (endpt %d), minor %d\n", driver_label, driver_endpt, driver_minor); #endif /* Initialize resources. */ fbd_buf = alloc_contig(BUF_SIZE, 0, NULL); assert(fbd_buf != NULL); if ((r = getticks(&uptime)) != OK) panic("getuptime failed (%d)\n", r); srand48(uptime); /* Announce we are up! */ blockdriver_announce(type); return OK; }
/*===========================================================================* * fs_readsuper * *===========================================================================*/ PUBLIC int fs_readsuper() { /* This function reads the superblock of the partition, gets the root inode * and sends back the details of them. Note, that the FS process does not * know the index of the vmnt object which refers to it, whenever the pathname * lookup leaves a partition an ELEAVEMOUNT error is transferred back * so that the VFS knows that it has to find the vnode on which this FS * process' partition is mounted on. */ struct inode *root_ip; cp_grant_id_t label_gid; size_t label_len; int r; endpoint_t driver_e; int readonly, isroot; fs_dev = (dev_t) fs_m_in.REQ_DEV; label_gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; label_len = (size_t) fs_m_in.REQ_PATH_LEN; readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0; isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0; if (label_len > sizeof(fs_dev_label)) return(EINVAL); r = sys_safecopyfrom(fs_m_in.m_source, label_gid, (vir_bytes) 0, (vir_bytes) fs_dev_label, label_len, D); if (r != OK) { printf("MFS %s:%d safecopyfrom failed: %d\n", __FILE__, __LINE__, r); return(EINVAL); } r = ds_retrieve_label_endpt(fs_dev_label, &driver_e); if (r != OK) { printf("MFS %s:%d ds_retrieve_label_endpt failed for '%s': %d\n", __FILE__, __LINE__, fs_dev_label, r); return(EINVAL); } /* Map the driver endpoint for this major */ bdev_driver(fs_dev, driver_e); /* Open the device the file system lives on. */ if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT) ) != OK) { return(EINVAL); } /* Fill in the super block. */ superblock.s_dev = fs_dev; /* read_super() needs to know which dev */ r = read_super(&superblock); /* Is it recognized as a Minix filesystem? */ if (r != OK) { superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(r); } set_blocksize(&superblock); /* Get the root inode of the mounted file system. */ if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { printf("MFS: couldn't get root inode\n"); superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } if(root_ip->i_mode == 0) { printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); put_inode(root_ip); superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } superblock.s_rd_only = readonly; superblock.s_is_root = isroot; /* Root inode properties */ fs_m_out.RES_INODE_NR = root_ip->i_num; fs_m_out.RES_MODE = root_ip->i_mode; fs_m_out.RES_FILE_SIZE_LO = root_ip->i_size; fs_m_out.RES_UID = root_ip->i_uid; fs_m_out.RES_GID = root_ip->i_gid; fs_m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */ return(r); }