/** * @param name is prined before the tag value. * @param tag is the tag id. * @param wc is the size of the property in words. */ static void print_prop(char * name, uint32_t tag, size_t wc) { uint32_t mbuf[6 + wc] __attribute__((aligned (16))); int err; char buf[80]; char * s; mbuf[0] = sizeof(mbuf); /* Size */ mbuf[1] = BCM2835_PROP_REQUEST; /* Request */ /* Tags */ mbuf[2] = tag; mbuf[3] = wc * 4; mbuf[4] = 0; /* Request len always zero */ mbuf[5 + wc] = BCM2835_PROP_TAG_END; err = bcm2835_prop_request(mbuf); if (err) { KERROR(KERROR_INFO, "bcm2835_info %s: ERR %d\n", name, err); return; } s = buf; for (size_t i = 0; i < wc; i++) { s += ksprintf(s, buf + sizeof(buf) - s, "%x ", mbuf[5 + i]) - 1; } KERROR(KERROR_INFO, "bcm2835_info %s: %s\n", name, buf); }
/** * Get kmalloc'd array for full path name. */ static char * format_fpath(struct fatfs_inode * indir, const char * name) { char * fpath; size_t fpath_size; #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "format_fpath(indir \"%s\", name \"%s\")\n", indir->in_fpath, name); #endif fpath_size = strlenn(name, NAME_MAX + 1) + strlenn(indir->in_fpath, NAME_MAX + 1) + 6; fpath = kmalloc(fpath_size); if (!fpath) return NULL; ksprintf(fpath, fpath_size, "%s/%s", indir->in_fpath, name); #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "Formatted \"%s\" as \"%s\"\n", name, fpath); #endif return fpath; }
/* * TODO If fb is a default kerror output device then a fb should be registered * before kerror is initialized but there is no obvious way to do that, since * we definitely want to keep fb constructors in driver files to support * dynamic loading, in the future, just for example. */ int fb_register(struct fb_conf * fb) { const int minor = atomic_inc(&fb_minor); dev_t devid_tty; dev_t devid_mm; int err; devid_tty = DEV_MMTODEV(VDEV_MJNR_FB, minor); devid_mm = DEV_MMTODEV(VDEV_MJNR_FBMM, minor); fb_console_init(fb); err = fb_console_maketty(fb, devid_tty); if (err) { KERROR(KERROR_ERR, "FB: maketty failed\n"); return err; } err = fb_makemmdev(fb, devid_mm); if (err) { KERROR(KERROR_ERR, "FB: makemmdev failed\n"); return err; } draw_splash(fb); fb_console_write(fb, "FB ready\r\n"); return 0; }
/* * Reads the file from the path into a temporary buffer, and then attempt to * load it as a kernel module. * * @param path Path to the kernel module * @param err Pointer to an integer in which to store a more detailed error * @return true if success, false if error. */ bool module_load_from_file(char *path, int *err) { // Attempt to open file fs_file_handle_t *module = hal_vfs_fopen(path, kFSFileModeReadOnly); if(module) { // Reject modules > 1MB in size fs_file_t *file = hal_vfs_handle_to_file(module); if(file->size > MODULE_MAX_SIZE) { KERROR("%s is %u bytes, max %u bytes", path, (unsigned int) file->size, MODULE_MAX_SIZE); return false; } // Get buffer and zero it void *buf = (void *) paging_module_buffer(); memclr(buf, MODULE_MAX_SIZE); // Read entire file hal_vfs_fread(buf, file->size, module); // Clean up hal_vfs_fclose(module); // Perform module loading module_load(buf, file->i.name); } else { KERROR("Can't open '%s' for module read", path); } return false; }
/** * ATAG scanner. * @note This function is called before intializers. */ void atag_scan(uint32_t fw, uint32_t mtype, uint32_t * atag_addr) { uint32_t * atags; sysinfo.mtype = mtype; if (atag_addr[0] == 0 || atag_addr[1] != ATAG_CORE) { KERROR(KERROR_WARN, "No ATAGs!\n"); return; } for (atags = atag_addr; atags < (uint32_t *)0x8000; atags += 1) { switch (atags[1]) { case ATAG_CORE: KERROR(KERROR_INFO, "[ATAG_CORE] flags: %x, page size: %u, rootdev: %u\n", atags[2], atags[3], atags[4]); atags += atags[0]-1; break; case ATAG_MEM: KERROR(KERROR_INFO, "[ATAG_MEM] size: %x, start: %x\n", atags[2], atags[3]); sysinfo_setmem((size_t)atags[3], (size_t)atags[2]); atags += atags[0]-1; break; case ATAG_VIDEOTEXT: atags += atags[0]-1; break; case ATAG_RAMDISK: atags += atags[0]-1; break; case ATAG_INITRD2: atags += atags[0]-1; break; case ATAG_SERIAL: atags += atags[0]-1; break; case ATAG_REVISION: atags += atags[0]-1; break; case ATAG_VIDEOLFB: atags += atags[0]-1; break; case ATAG_CMDLINE: atags += 2; KERROR(KERROR_INFO, "[ATAG_CMDLINE] : %s\n", (char *)atags); sysinfo_cmdline((const char *)atags); atags += atags[0]-1; break; default: break; } } }
int ptmapper_alloc(mmu_pagetable_t * pt) { size_t block; size_t addr; size_t size = 0; /* Size in bitmap */ size_t bsize = 0; /* Size in bytes */ size_t balign; int retval = 0; switch (pt->type) { case MMU_PTT_MASTER: size = PTM_MASTER; bsize = MMU_PTSZ_MASTER; balign = 0x10; /* TODO Depends on HW */ break; case MMU_PTT_COARSE: size = PTM_COARSE; bsize = MMU_PTSZ_COARSE; balign = 0x1; break; default: panic("pt size can't be zero"); } /* Try to allocate a new page table */ if (!PTM_ALLOC(&block, size, balign)) { #if configDEBUG != 0 char buf[80]; #endif addr = PTM_BLOCK2ADDR(block); #if configDEBUG >= KERROR_DEBUG ksprintf(buf, sizeof(buf), "Alloc pt %u bytes @ %x", bsize, addr); KERROR(KERROR_DEBUG, buf); #endif pt->pt_addr = addr; if (pt->type == MMU_PTT_MASTER) { pt->master_pt_addr = addr; } /* Accounting for sysctl */ ptm_nr_pt++; ptm_mem_free -= bsize; } else { #if configDEBUG >= KERROR_ERR KERROR(KERROR_ERR, "Out of pt memory"); #endif retval = -1; } return retval; }
void ptmapper_free(mmu_pagetable_t * pt) { size_t block; size_t size = 0; /* Size in bitmap */ size_t bsize = 0; /* Size in bytes */ switch (pt->type) { case MMU_PTT_MASTER: size = PTM_MASTER; bsize = MMU_PTSZ_MASTER; break; case MMU_PTT_COARSE: size = PTM_COARSE; bsize = MMU_PTSZ_COARSE; break; default: KERROR(KERROR_ERR, "Attemp to free an invalid page table."); return; } block = PTM_ADDR2BLOCK(pt->pt_addr); PTM_FREE(block, size); /* Accounting for sysctl */ ptm_nr_pt--; ptm_mem_free += bsize; }
DRESULT fatfs_disk_ioctl(uint8_t pdrv, unsigned cmd, void * buff, size_t bsize) { file_t * file; ssize_t err; #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "fatfs_disk_ioctl(pdrv %u, cmd %u, buff %p, bsize %u)\n", (uint32_t)pdrv, (uint32_t)cmd, buff, (uint32_t)bsize); #endif if (pdrv >= configFATFS_MAX_MOUNTS || !fatfs_sb_arr[pdrv]) return RES_PARERR; file = &fatfs_sb_arr[pdrv]->ff_devfile; if (!file->vnode->vnode_ops->ioctl) return RES_ERROR; switch (cmd) { case CTRL_SYNC: case CTRL_ERASE_SECTOR: /* TODO Not implemented yet. */ return 0; break; default: break; } err = file->vnode->vnode_ops->ioctl(file, cmd, buff, bsize); if (err) return RES_ERROR; return 0; }
int fatfs_mknod(vnode_t * dir, const char * name, int mode, void * specinfo, vnode_t ** result) { struct fatfs_inode * indir = get_inode_of_vnode(dir); struct fatfs_inode * res = NULL; char * in_fpath; int err; #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "fatfs_mknod(dir %p, name \"%s\", mode %u, specinfo %p, result %p)\n", dir, name, mode, specinfo, result); #endif if (!S_ISDIR(dir->vn_mode)) return -ENOTDIR; if ((mode & S_IFMT) != S_IFREG) return -ENOTSUP; /* FAT only suports regular files. */ if (specinfo) return -EINVAL; /* specinfo not supported. */ in_fpath = format_fpath(indir, name); if (!in_fpath) return -ENOMEM; err = create_inode(&res, get_ffsb_of_sb(dir->sb), in_fpath, hash32_str(in_fpath, 0), O_CREAT); if (err) { kfree(in_fpath); return fresult2errno(err); } if (result) *result = &res->in_vnode; fatfs_chmod(&res->in_vnode, mode); #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "mkdod() ok\n"); #endif return 0; }
struct buf * vr_rclone(struct buf * old_region) { struct buf * new_region; const size_t rsize = old_region->b_bufsize; /* "Lock", ensure that the region is not freed during the operation. */ vrref(old_region); new_region = geteblk(rsize); if (!new_region) { KERROR(KERROR_ERR, "Out of memory"); return 0; } #if configDEBUG >= KERROR_DEBUG { char buf[80]; ksprintf(buf, sizeof(buf), "clone %x -> %x, %u bytes", old_region->b_data, new_region->b_data, rsize); KERROR(KERROR_DEBUG, buf); } #endif /* Copy data */ memcpy((void *)(new_region->b_data), (void *)(old_region->b_data), rsize); /* Copy attributes */ new_region->b_uflags = ~VM_PROT_COW & old_region->b_uflags; new_region->b_mmu.vaddr = old_region->b_mmu.vaddr; /* num_pages already set */ new_region->b_mmu.ap = old_region->b_mmu.ap; new_region->b_mmu.control = old_region->b_mmu.control; /* paddr already set */ new_region->b_mmu.pt = old_region->b_mmu.pt; vm_updateusr_ap(new_region); /* Release "lock". */ brelse(old_region); return new_region; }
/** * Read sector(s). * @param pdrv is a (physical) drive nmuber to identify the drive. * @param buff is a data buffer to store read data. * @param sector is a sector address in LBA. * @param count is the number of bytes to read. * */ DRESULT fatfs_disk_read(uint8_t pdrv, uint8_t * buff, DWORD sector, unsigned int count) { file_t * file; vnode_t * vnode; struct uio uio; ssize_t retval; if (pdrv >= configFATFS_MAX_MOUNTS || !fatfs_sb_arr[pdrv]) return RES_PARERR; file = &fatfs_sb_arr[pdrv]->ff_devfile; vnode = file->vnode; retval = vnode->vnode_ops->lseek(file, sector, SEEK_SET); if (retval < 0) { #ifdef configFATFS_DEBUG KERROR(KERROR_ERR, "%s(): err %i\n", __func__, retval); #endif return RES_ERROR; } uio_init_kbuf(&uio, buff, count); retval = file->vnode->vnode_ops->read(file, &uio, count); if (retval < 0) { #ifdef configFATFS_DEBUG KERROR(KERROR_ERR, "fatfs_disk_read(): err %i\n", retval); #endif return RES_ERROR; } if (retval != (ssize_t)count) { #ifdef configFATFS_DEBUG KERROR(KERROR_WARN, "retval(%i) != count(%i)\n", (uint32_t)retval, (uint32_t)count); #endif return RES_PARERR; } return 0; }
/** * Check an MBR signature. */ static int check_signature(uint8_t * block_0) { if ((block_0[0x1fe] != 0x55) || (block_0[0x1ff] != 0xaa)) { KERROR(KERROR_ERR, "MBR: Invalid signature (%x %x)\n", block_0[0x1fe], block_0[0x1ff]); return -ENOENT; } return 0; }
static int load_sections(struct proc_info * proc, file_t * file, struct elf32_header * elfhdr, struct elf32_phdr * phdr, uintptr_t rbase, uintptr_t * vaddr_base) { int e_type = elfhdr->e_type; size_t phnum = elfhdr->e_phnum; for (size_t i = 0; i < phnum; i++) { struct buf * sect; int err; if (!(phdr[i].p_type == PT_LOAD && phdr[i].p_memsz != 0)) continue; if ((err = load_section(§, file, rbase, &phdr[i]))) return err; if (e_type == ET_EXEC && i < 2) { const int reg_nr = (i == 0) ? MM_CODE_REGION : MM_HEAP_REGION; if (i == 0) *vaddr_base = phdr[i].p_vaddr + rbase; err = vm_replace_region(proc, sect, reg_nr, VM_INSOP_MAP_REG); if (err) { KERROR(KERROR_ERR, "Failed to replace a region\n"); return err; } } else { err = vm_insert_region(proc, sect, VM_INSOP_MAP_REG); if (err < 0) { KERROR(KERROR_ERR, "Failed to insert a region\n"); return -1; } } } return 0; }
static int read_block_0(uint8_t * block_0, file_t * file) { struct uio uio; int ret; uio_init_kbuf(&uio, block_0, MBR_SIZE); /* Read the first 512 bytes. */ ret = dev_read(file, &uio, MBR_SIZE); if (ret < 0) { KERROR(KERROR_ERR, "MBR: block_read failed (%i)\n", ret); return ret; } else if (ret != MBR_SIZE) { KERROR(KERROR_ERR, "MBR: Failed to read %d bytes, only %d bytes read\n", MBR_SIZE, ret); return -ENOENT; } return 0; }
/* * Polls a certain channel until the command either completes successfully, or * an abnormal condition happens. */ int ata_poll_ready(ata_driver_t *drv, uint8_t channel, bool advanced_check) { // Wait for drive to assert BSY for(int i = 0; i < 4; i++) { ata_reg_read(drv, channel, ATA_REG_ALTSTATUS); } unsigned int startCycles = kern_get_ticks(); // Wait for the device to no longer be busy while(ata_reg_read(drv, channel, ATA_REG_STATUS) & ATA_SR_BSY) { // Allow requests to time out if(kern_get_ticks() - startCycles > ATA_WAIT_TIMEOUT) { KERROR("IDE: device took too long (%u ticks)", (unsigned int) (kern_get_ticks() - startCycles)); return ATA_ERR_TIMEOUT; } } //advanced_check = false; // If set, we perform more in-depth checking if(advanced_check) { // Read status register uint8_t state = ata_reg_read(drv, channel, ATA_REG_STATUS); if(state & ATA_SR_ERR) { // Error executing command return 2; } else if(state & ATA_SR_DF) { // Device fault return 1; } else if(!(state & ATA_SR_DRQ)) { // BSY = 0; DF = 0; ERR = 0; DRQ = 0 KERROR("IDE: No data after %u timer ticks", (unsigned int) (kern_get_ticks() - startCycles)); return 3; } } // Hooray everything is happy return 0; }
vnode_t * fs_create_pseudofs_root(fs_t * newfs, int majornum) { int err; vnode_t * rootnode; /* * We use a little trick here and create a temporary vnode that will be * destroyed after succesful mount. */ rootnode = kzalloc(sizeof(vnode_t)); if (!rootnode) return NULL; /* Temp root dir */ rootnode->vn_next_mountpoint = rootnode; vrefset(rootnode, 1); mtx_init(&rootnode->vn_lock, VN_LOCK_TYPE, VN_LOCK_OPT); err = fs_mount(rootnode, "", "ramfs", 0, "", 1); if (err) { KERROR(KERROR_ERR, "Unable to create a pseudo fs root vnode for %s (%i)\n", newfs->fsname, err); return NULL; } rootnode = rootnode->vn_next_mountpoint; kfree(rootnode->vn_prev_mountpoint); rootnode->vn_prev_mountpoint = rootnode; rootnode->vn_next_mountpoint = rootnode; newfs->fs_majornum = majornum; newfs->sblist_head = rootnode->sb->fs->sblist_head; rootnode->sb->fs = newfs; rootnode->sb->vdev_id = DEV_MMTODEV(majornum, 0); return rootnode; }
// Opens a file, optionally creating it. static fs_file_handle_t *fat32_file_open(void *superblock, char *path, fs_file_open_mode_t mode) { // Validate input if(path) { // Paths that don't start with a slash are invalid if(path[0] != '/') { #if PRINT_ERROR KERROR("Rejecting invalid path '%s'", path); #endif return NULL; } fs_fat32 *fs = (fs_fat32 *) superblock; fs_file_handle_t *handle = fs->get_file_handle(path, mode); // Set the file mode handle->mode = mode; return handle; } return NULL; }
static int clone_code_region(struct proc_info * new_proc, struct proc_info * old_proc) { struct buf * vm_reg_tmp; /* Copy code region pointer. */ vm_reg_tmp = (*old_proc->mm.regions)[MM_CODE_REGION]; if (!vm_reg_tmp) { KERROR(KERROR_ERR, "Old proc code region can't be null\n"); return -EINVAL; /* Not allowed but this shouldn't happen. */ } /* * In Zeke we always have at least one read-only code region by design so * we don't have to COW it or do anything fancy with it, instead we just * take a reference to the code region of the old process. */ if (vm_reg_tmp->vm_ops->rref) vm_reg_tmp->vm_ops->rref(vm_reg_tmp); (*new_proc->mm.regions)[MM_CODE_REGION] = vm_reg_tmp; return 0; }
static void mount_tmp_rootfs(void) { const char failed[] = "Failed to mount rootfs"; vnode_t * tmp = NULL; struct proc_info * kernel_proc; int ret; kernel_proc = proc_ref(0); if (!kernel_proc) { panic(failed); } /* No need to keep the ref because it won't go away. */ proc_unref(kernel_proc); /* Root dir */ tmp = kzalloc_crit(sizeof(vnode_t)); kernel_proc->croot = tmp; kernel_proc->croot->vn_next_mountpoint = kernel_proc->croot; kernel_proc->croot->vn_prev_mountpoint = kernel_proc->croot; mtx_init(&tmp->vn_lock, MTX_TYPE_SPIN, 0); vrefset(kernel_proc->croot, 2); ret = fs_mount(kernel_proc->croot, "", "ramfs", 0, "", 1); if (ret) { KERROR(KERROR_ERR, "%s : %i\n", failed, ret); goto out; } kernel_proc->croot->vn_next_mountpoint->vn_prev_mountpoint = kernel_proc->croot->vn_next_mountpoint; kernel_proc->croot = kernel_proc->croot->vn_next_mountpoint; kernel_proc->cwd = kernel_proc->croot; out: kfree(tmp); }
static vnode_t * create_root(struct fatfs_sb * fatfs_sb) { char * rootpath; long vn_hash; struct fatfs_inode * in; int err; rootpath = kzalloc(2); if (!rootpath) return NULL; vn_hash = hash32_str(rootpath, 0); err = create_inode(&in, fatfs_sb, rootpath, vn_hash, O_DIRECTORY | O_RDWR); if (err) { KERROR(KERROR_ERR, "Failed to init a root vnode for fatfs (%d)\n", err); return NULL; } in->in_fpath = rootpath; vrefset(&in->in_vnode, 1); return &in->in_vnode; }
struct tty * tty_alloc(const char * drv_name, dev_t dev_id, const char * dev_name, size_t data_size) { struct dev_info * dev; struct tty * tty; dev = kzalloc(sizeof(struct dev_info) + sizeof(struct tty) + data_size); if (!dev) return NULL; tty = (struct tty *)((uintptr_t)dev + sizeof(struct dev_info)); dev->dev_id = dev_id; dev->drv_name = drv_name; strlcpy(dev->dev_name, dev_name, sizeof(dev->dev_name)); dev->flags = DEV_FLAGS_MB_READ | DEV_FLAGS_WR_BT_MASK; dev->block_size = 1; dev->read = tty_read; dev->write = tty_write; dev->lseek = tty_lseek; dev->open_callback = tty_open_callback; dev->close_callback = tty_close_callback; dev->ioctl = tty_ioctl; dev->opt_data = tty; /* * Linux defaults: * tty->conf.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | * ECHOKE | IEXTEN; */ /* * TODO termios support * *supported now* * iflags: - * oflags: - * cflags: - * lfags: - */ /* TODO Better winsize support. */ tty->winsize = (struct winsize){ .ws_row = 24, .ws_col = 80, .ws_xpixel = 0, .ws_ypixel = 0, }; return tty; } void tty_free(struct tty * tty) { struct dev_info * dev; dev = (struct dev_info *)((uintptr_t)tty - sizeof(struct dev_info)); KASSERT(dev->opt_data == tty, "opt_data changed or invalid tty"); kfree(dev); } struct dev_info * tty_get_dev(struct tty * tty) { return (struct dev_info *)((uintptr_t)tty - sizeof(struct dev_info)); } int make_ttydev(struct tty * tty) { struct dev_info * dev; vnode_t * vn; dev = (struct dev_info *)((uintptr_t)tty - sizeof(struct dev_info)); KASSERT(dev->opt_data == tty, "opt_data changed or invalid tty"); if (tty->tty_vn != NULL) { KERROR(KERROR_ERR, "A device file is already created for this tty\n"); return -EMLINK; } if (make_dev(dev, 0, 0, 0666, &vn)) { KERROR(KERROR_ERR, "Failed to make a tty dev.\n"); return -ENODEV; } tty->tty_vn = vn; return 0; } void destroy_ttydev(struct tty * tty) { struct dev_info * dev; dev = (struct dev_info *)((uintptr_t)tty - sizeof(struct dev_info)); KASSERT(dev->opt_data == tty, "opt_data changed or invalid tty"); destroy_dev(tty->tty_vn); } static ssize_t tty_read(struct dev_info * devnfo, off_t blkno, uint8_t * buf, size_t bcount, int oflags) { struct tty * tty = (struct tty *)devnfo->opt_data; KASSERT(tty, "opt_data should have a tty"); return tty->read(tty, blkno, buf, bcount, oflags); } static ssize_t tty_write(struct dev_info * devnfo, off_t blkno, uint8_t * buf, size_t bcount, int oflags) { struct tty * tty = (struct tty *)devnfo->opt_data; ssize_t retval; KASSERT(tty, "opt_data should have a tty"); retval = tty->write(tty, blkno, buf, bcount, oflags); if (retval > 0) { off_t n = tty->write_count + retval; tty->write_count = (n < 0) ? -n : n; } return retval; } static off_t tty_lseek(file_t * file, struct dev_info * devnfo, off_t offset, int whence) { struct tty * tty = (struct tty *)devnfo->opt_data; /* * Many unices will return the number of written characters if whence is * SEEK_SET and the file is a tty, and some will return -ESPIPE. We support * the write count. */ if (whence == SEEK_SET) return tty->write_count; /* * Some drivers may use seek_pos as an index variable and on this kernel * we promise to return it if lseek is called with offset zero and SEEK_CUR * set as a whence. */ if (offset == 0 && whence == SEEK_CUR) return file->seek_pos; return -ESPIPE; } static void tty_open_callback(struct proc_info * p, file_t * file, struct dev_info * devnfo) { struct tty * tty = (struct tty *)devnfo->opt_data; KASSERT(tty, "opt_data should have a tty"); if (tty->open_callback) tty->open_callback(file, tty); } static void tty_close_callback(struct proc_info * p, file_t * file, struct dev_info * devnfo) { struct tty * tty = (struct tty *)devnfo->opt_data; KASSERT(tty, "opt_data should have a tty"); if (tty->close_callback) tty->close_callback(file, tty); } static int tty_ioctl(struct dev_info * devnfo, uint32_t request, void * arg, size_t arg_len) { int err; struct tty * tty = (struct tty *)(devnfo->opt_data); if (!tty) return -EINVAL; /* * First call ioctl of the device driver since it may override some ioctls * defined here. */ if (tty->ioctl) { err = tty->ioctl(devnfo, request, arg, arg_len); if (err == 0 || err != -EINVAL) return err; } /* otherwise check if we can handle it here */ switch (request) { case IOCTL_GTERMIOS: if (arg_len < sizeof(struct termios)) return -EINVAL; memcpy(arg, &(tty->conf), sizeof(struct termios)); break; case IOCTL_STERMIOS: if (arg_len < sizeof(struct termios)) return -EINVAL; err = priv_check(&curproc->cred, PRIV_TTY_SETA); if (err) return err; memcpy(&(tty->conf), arg, sizeof(struct termios)); tty->setconf(&tty->conf); break; case IOCTL_TIOCGWINSZ: if (arg_len < sizeof(struct winsize)) return -EINVAL; memcpy(arg, &(tty->winsize), sizeof(struct winsize)); break; case IOCTL_TIOCSWINSZ: if (arg_len < sizeof(struct winsize)) return -EINVAL; memcpy(&(tty->winsize), arg, sizeof(struct winsize)); break; /* * This should be probably overriden and "optimized" in * the low level driver. Also if there is any muxing on * any lower level flush may do stupid things if done * by this function. */ case IOCTL_TTYFLUSH: if (arg_len < sizeof(int)) { return -EINVAL; } else { int control = (int)arg; uint8_t buf[5]; switch (control) { case TCIFLUSH: while (tty->read(tty, 0, buf, sizeof(buf), O_NONBLOCK) >= 0); break; default: return -EINVAL; } } break; case IOCTL_TCSBRK: /* NOP */ break; default: return -EINVAL; } return 0; }
int _mtx_lock(mtx_t * mtx, char * whr) #endif { int ticket; const int sleep_mode = MTX_OPT(mtx, MTX_OPT_SLEEP); #ifdef configLOCK_DEBUG unsigned deadlock_cnt = 0; #endif if (mtx->mtx_type == MTX_TYPE_TICKET) { ticket = atomic_inc(&mtx->ticket.queue); } if (MTX_OPT(mtx, MTX_OPT_DINT)) { cpu_istate = get_interrupt_state(); disable_interrupt(); } while (1) { #ifdef configLOCK_DEBUG /* * TODO Deadlock detection threshold should depend on lock type and * current priorities. */ if (++deadlock_cnt >= configSCHED_HZ * (configKLOCK_DLTHRES + 1)) { char * lwhr = (mtx->mtx_ldebug) ? mtx->mtx_ldebug : "?"; KERROR(KERROR_DEBUG, "Deadlock detected:\n%s WAITING\n%s LOCKED\n", whr, lwhr); deadlock_cnt = 0; } #endif if (sleep_mode && (current_thread->wait_tim == -2)) return -EWOULDBLOCK; switch (mtx->mtx_type) { case MTX_TYPE_SPIN: if (!test_and_set((int *)(&mtx->mtx_lock))) goto out; break; case MTX_TYPE_TICKET: if (atomic_read(&mtx->ticket.dequeue) == ticket) { mtx->mtx_lock = 1; goto out; } thread_yield(THREAD_YIELD_LAZY); break; default: MTX_TYPE_NOTSUP(); if (MTX_OPT(mtx, MTX_OPT_DINT)) set_interrupt_state(cpu_istate); return -ENOTSUP; } #ifdef configMP cpu_wfe(); /* Sleep until event. */ #endif } out: /* Handle priority ceiling. */ priceil_set(mtx); #ifdef configLOCK_DEBUG mtx->mtx_ldebug = whr; #endif return 0; }
int mbr_register(int fd, int * part_count) { file_t * file; vnode_t * parent_vnode; struct dev_info * parent; uint8_t * block_0 = NULL; int parts = 0; int retval = 0; #ifdef configMBR_DEBUG KERROR(KERROR_DEBUG, "%s(fd: %d, part_count: %p)\n", __func__, fd, part_count); #endif file = fs_fildes_ref(curproc->files, fd, 1); parent_vnode = file->vnode; parent = (struct dev_info *)parent_vnode->vn_specinfo; if (!(S_ISBLK(parent_vnode->vn_mode) || S_ISCHR(parent_vnode->vn_mode))) { KERROR(KERROR_ERR, "MBR: not a device\n"); retval = -ENODEV; goto fail; } /* Check the validity of the parent device. */ if (!parent) { KERROR(KERROR_ERR, "MBR: invalid parent device\n"); retval = -ENODEV; goto fail; } block_0 = kmalloc(MBR_SIZE); if (!block_0) { retval = -ENOMEM; goto fail; } #ifdef configMBR_DEBUG KERROR(KERROR_DEBUG, "MBR: reading block 0 from device %s\n", parent->dev_name); #endif retval = read_block_0(block_0, file); if (retval) goto fail; retval = check_signature(block_0); if (retval) goto fail; #ifdef configMBR_DEBUG KERROR(KERROR_DEBUG, "MBR: found valid MBR on device %s\n", parent->dev_name); #endif /* * If parent block size is not MBR_SIZE, we have to coerce start_block * and blocks to fit. */ if (parent->block_size < MBR_SIZE) { /* We do not support parent device block sizes < 512 */ KERROR(KERROR_ERR, "MBR: block size of %s is too small (%i)\n", parent->dev_name, parent->block_size); retval = -ENOTSUP; goto fail; } uint32_t block_size_adjust = parent->block_size / MBR_SIZE; if (parent->block_size % MBR_SIZE) { /* * We do not support parent device block sizes that are not * multiples of 512. */ KERROR(KERROR_ERR, "MBR: block size of %s is not a multiple of 512 (%i)\n", parent->dev_name, parent->block_size); retval = -ENOTSUP; goto fail; } #ifdef configMBR_DEBUG if (block_size_adjust > 1) { KERROR(KERROR_DEBUG, "MBR: block_size_adjust: %i\n", block_size_adjust); } #endif int major_num = DEV_MAJOR(parent->dev_id) + 1; for (size_t i = 0; i < 4; i++) { size_t p_offset = 0x1be + (i * 0x10); struct mbr_dev * d; if (block_0[p_offset + 4] == 0x00) { /* Invalid partition */ continue; } d = kzalloc(sizeof(struct mbr_dev)); if (!d) { KERROR(KERROR_ERR, "MBR: Out of memory"); retval = -ENOMEM; break; } d->dev.dev_id = DEV_MMTODEV(major_num, mbr_dev_count); d->dev.drv_name = driver_name; ksprintf(d->dev.dev_name, sizeof(d->dev.dev_name), "%sp%u", parent->dev_name, i); d->dev.read = mbr_read; d->dev.write = (parent->write) ? mbr_write : NULL; d->dev.block_size = parent->block_size; d->dev.flags = parent->flags; d->part_no = i; d->part_id = block_0[p_offset + 4]; d->start_block = read_word(block_0, p_offset + 8); d->blocks = read_word(block_0, p_offset + 12); d->parent = parent; /* Adjust start_block and blocks to the parent block size */ if (d->start_block % block_size_adjust) { KERROR(KERROR_ERR, "MBR: partition number %i on %s does not start on a block " "boundary (%i).\n", d->part_no, parent->dev_name, d->start_block); retval = -EFAULT; goto fail; } d->start_block /= block_size_adjust; if (d->blocks % block_size_adjust) { KERROR(KERROR_ERR, "MBR: partition number %i on %s does not have a length " "that is an exact multiple of the block length (%i).\n", d->part_no, parent->dev_name, d->start_block); retval = -EFAULT; goto fail; } d->blocks /= block_size_adjust; d->dev.num_blocks = d->blocks; #ifdef configMBR_DEBUG KERROR(KERROR_DEBUG, "MBR: partition number %i (%s) of type %x, " "start sector %u, sector count %u, p_offset %03x\n", d->part_no, d->dev.dev_name, d->part_id, d->start_block, d->blocks, p_offset); #endif make_dev(&d->dev, 0, 0, 0666, NULL); mbr_dev_count++; parts++; /* Register the fs */ //register_fs__((struct dev_info *)d, d->part_id); /* TODO Register the fs dev with devfs */ } KERROR(KERROR_INFO, "MBR: found total of %i partition(s)\n", parts); fail: kfree(block_0); fs_fildes_ref(curproc->files, fd, -1); if (retval != 0) { KERROR(KERROR_ERR, "MBR registration failed on device: \"%s\"\n", parent->dev_name); } return retval; }
int fatfs_stat(vnode_t * vnode, struct stat * buf) { struct fatfs_sb * ffsb = get_ffsb_of_sb(vnode->sb); struct fatfs_inode * in = get_inode_of_vnode(vnode); FILINFO fno; struct stat mp_stat = { .st_uid = 0, .st_gid = 0 }; size_t blksize = ffsb->ff_fs.ssize; int err; memset(&fno, 0, sizeof(fno)); err = get_mp_stat(vnode, &mp_stat); if (err) { if (err == -EINPROGRESS) { #ifdef configFATFS_DEBUG KERROR(KERROR_WARN, "vnode->sb->mountpoint should be set\n"); #endif } else { #ifdef configFATFS_DEBUG KERROR(KERROR_WARN, "get_mp_stat() returned error (%d)\n", err); #endif return err; } } /* Can't stat FAT root */ if (vnode == vnode->sb->root) { memcpy(buf, &mp_stat, sizeof(struct stat)); return 0; } err = f_stat(&ffsb->ff_fs, in->in_fpath, &fno); if (err) { #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "f_stat(fs %p, fpath \"%s\", fno %p) failed\n", &ffsb->ff_fs, in->in_fpath, &fno); #endif return fresult2errno(err); } buf->st_dev = vnode->sb->vdev_id; buf->st_ino = vnode->vn_num; buf->st_mode = vnode->vn_mode; buf->st_nlink = 1; /* Always one link on FAT. */ buf->st_uid = mp_stat.st_uid; buf->st_gid = mp_stat.st_gid; buf->st_size = fno.fsize; /* TODO Times */ #if 0 buf->st_atim; buf->st_mtim; buf->st_ctim; buf->st_birthtime; #endif buf->st_flags = fattrib2uflags(fno.fattrib); buf->st_blksize = blksize; buf->st_blocks = fno.fsize / blksize + 1; /* Best guess. */ return 0; } int fatfs_chmod(vnode_t * vnode, mode_t mode) { struct fatfs_sb * ffsb = get_ffsb_of_sb(vnode->sb); struct fatfs_inode * in = get_inode_of_vnode(vnode); uint8_t attr = 0; const uint8_t mask = AM_RDO; int err; if (!(mode & (S_IWUSR | S_IWGRP | S_IWOTH))) attr |= AM_RDO; err = fresult2errno(f_chmod(&ffsb->ff_fs, in->in_fpath, attr, mask)); if (!err) vnode->vn_mode = mode; return err; } /* * Note: Thre is practically two ways to set AM_RDO, either * by using chmod() or by this chflags(). */ int fatfs_chflags(vnode_t * vnode, fflags_t flags) { struct fatfs_sb * ffsb = get_ffsb_of_sb(vnode->sb); struct fatfs_inode * in = get_inode_of_vnode(vnode); uint8_t attr = 0; const uint8_t mask = AM_RDO | AM_ARC | AM_SYS | AM_HID; FRESULT fresult; if (flags & UF_SYSTEM) attr |= AM_SYS; if (flags & UF_ARCHIVE) attr |= AM_ARC; if (flags & UF_READONLY) attr |= AM_RDO; if (flags & UF_HIDDEN) attr |= AM_HID; fresult = f_chmod(&ffsb->ff_fs, in->in_fpath, attr, mask); return fresult2errno(fresult); } /** * Initialize fatfs vnode data. * @param vnode is the target vnode to be initialized. */ static void init_fatfs_vnode(vnode_t * vnode, ino_t inum, mode_t mode, long vn_hash, struct fs_superblock * sb) { struct stat stat; #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "init_fatfs_vnode(vnode %p, inum %l, mode %o, vn_hash %u, sb %p)\n", vnode, (uint64_t)inum, mode, (uint32_t)vn_hash, sb); #endif fs_vnode_init(vnode, inum, sb, &fatfs_vnode_ops); vnode->vn_hash = vn_hash; if (S_ISDIR(mode)) mode |= S_IRWXU | S_IXGRP | S_IXOTH; vnode->vn_mode = mode | S_IRUSR | S_IRGRP | S_IROTH; fatfs_stat(vnode, &stat); vnode->vn_len = stat.st_size; if ((stat.st_flags & UF_READONLY) == 0) vnode->vn_mode |= S_IWUSR | S_IWGRP | S_IWOTH; } /** * Get mountpoint stat. */ static int get_mp_stat(vnode_t * vnode, struct stat * st) { struct fs_superblock * sb; vnode_t * mp; #ifdef configFATFS_DEBUG KASSERT(vnode, "Vnode was given"); KASSERT(vnode->sb, "Superblock is set"); #endif sb = vnode->sb; mp = sb->mountpoint; if (!mp) { /* We are probably mounting and mountpoint is not yet set. */ #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "mp not set\n"); #endif return -EINPROGRESS; } #ifdef configFATFS_DEBUG KASSERT(mp->vnode_ops->stat, "stat() is defined"); #endif return mp->vnode_ops->stat(mp, st); } static int fresult2errno(int fresult) { switch (fresult) { case FR_DISK_ERR: case FR_INVALID_OBJECT: case FR_INT_ERR: return -EIO; case FR_NOT_ENABLED: return -ENODEV; case FR_NO_FILESYSTEM: return -ENXIO; case FR_NO_FILE: case FR_NO_PATH: return -ENOENT; case FR_DENIED: return -EACCES; case FR_EXIST: return -EEXIST; case FR_WRITE_PROTECTED: return -EPERM; case FR_NOT_READY: return -EBUSY; case FR_INVALID_NAME: case FR_INVALID_DRIVE: case FR_MKFS_ABORTED: case FR_INVALID_PARAMETER: return -EINVAL; case FR_TIMEOUT: return -EWOULDBLOCK; case FR_NOT_ENOUGH_CORE: return -ENOMEM; case FR_TOO_MANY_OPEN_FILES: return -ENFILE; default: if (fresult != 0) /* Unknown error */ return -EIO; } return 0; }
/** * ATAG scanner. * @note This function is called before intializers. */ void atag_scan(uint32_t fw, uint32_t mtype, uint32_t * atag_addr) { uint32_t * atags; char msg[120]; sysinfo.mtype = mtype; if (*atag_addr != ATAG_CORE) { KERROR(KERROR_WARN, "No ATAGs!"); return; } for (atags = atag_addr; atags < (uint32_t *)0x8000; atags += 1) { switch (atags[1]) { case ATAG_CORE: ksprintf(msg, sizeof(msg), "[ATAG_CORE] flags: %x, page size: %u, rootdev: %u\n", atags[2], atags[3], atags[4]); KERROR(KERROR_INFO, msg); atags += atags[0]-1; break; case ATAG_MEM: ksprintf(msg, sizeof(msg), "[ATAG_MEM] size: %x, start: %x\n", atags[2], atags[3]); KERROR(KERROR_INFO, msg); atags += atags[0]-1; sysinfo.mem.size = (size_t)atags[2]; sysinfo.mem.start = (size_t)atags[3]; break; case ATAG_VIDEOTEXT: atags += atags[0]-1; break; case ATAG_RAMDISK: atags += atags[0]-1; break; case ATAG_INITRD2: atags += atags[0]-1; break; case ATAG_SERIAL: atags += atags[0]-1; break; case ATAG_REVISION: atags += atags[0]-1; break; case ATAG_VIDEOLFB: atags += atags[0]-1; break; case ATAG_CMDLINE: atags += 2; ksprintf(msg, sizeof(msg), "[ATAG_CMDLINE] : %s\n", (char *)atags); KERROR(KERROR_INFO, msg); atags += atags[0]-1; break; default: break; } } }
/** * Lookup for a vnode (file/dir) in FatFs. * First lookup form vfs_hash and if not found then read it from ff which will * probably read it via devfs interface. After the vnode has been created it * will be added to the vfs hashmap. In ff terminology all files and directories * that are in hashmap are also open on a file/dir handle, thus we'll have to * make sure we don't have too many vnodes in cache that have no references, to * avoid hitting any ff hard limits. */ static int fatfs_lookup(vnode_t * dir, const char * name, vnode_t ** result) { struct fatfs_inode * indir = get_inode_of_vnode(dir); struct fatfs_sb * sb = get_ffsb_of_sb(dir->sb); char * in_fpath; long vn_hash; struct vnode * vn = NULL; int err, retval = 0; KASSERT(dir != NULL, "dir must be set"); /* Format full path */ in_fpath = format_fpath(indir, name); if (!in_fpath) return -ENOMEM; /* * Emulate . and .. */ if (name[0] == '.' && name[1] != '.') { #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "Lookup emulating \".\"\n"); #endif (void)vref(dir); *result = dir; kfree(in_fpath); return 0; } else if (name[0] == '.' && name[1] == '.' && name[2] != '.') { #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "Lookup emulating \"..\"\n"); #endif if (VN_IS_FSROOT(dir)) { *result = dir->sb->mountpoint; kfree(in_fpath); return -EDOM; } else { size_t i = strlenn(in_fpath, NAME_MAX) - 4; while (in_fpath[i] != '/') { i--; } in_fpath[i] = '\0'; } } /* * Lookup from vfs_hash */ vn_hash = hash32_str(in_fpath, 0); err = vfs_hash_get( dir->sb, /* FS superblock */ vn_hash, /* Hash */ &vn, /* Retval */ fatfs_vncmp, /* Comparator */ in_fpath /* Compared fpath */ ); if (err) { retval = -EIO; goto fail; } if (vn) { /* found it in vfs_hash */ #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "vn found in vfs_hash (%p)\n", vn); #endif *result = vn; retval = 0; } else { /* not cached */ struct fatfs_inode * in; #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "vn not in vfs_hash\n"); #endif /* * Create a inode and fetch data from the device. * This also vrefs. */ err = create_inode(&in, sb, in_fpath, vn_hash, O_RDWR); if (err) { retval = err; goto fail; } in_fpath = NULL; /* shall not be freed. */ *result = &in->in_vnode; retval = 0; } fail: kfree(in_fpath); return retval; }
/** * Page table mapper init function. * @note This function should be called by mmu init. */ void ptmapper_init(void) { SUBSYS_INIT(); KERROR(KERROR_INFO, "ptmapper init started"); /* Allocate memory for mmu_pagetable_master */ if (ptmapper_alloc(&mmu_pagetable_master)) { panic("Can't allocate memory for master page table."); } mmu_pagetable_system.master_pt_addr = mmu_pagetable_master.master_pt_addr; if (ptmapper_alloc(&mmu_pagetable_system)) { panic("Can't allocate memory for system page table."); } /* Initialize system page tables */ mmu_init_pagetable(&mmu_pagetable_master); mmu_init_pagetable(&mmu_pagetable_system); /* Init regions */ /* Kernel ro region */ mmu_region_kernel.num_pages = MMU_PAGE_CNT_BY_RANGE( MMU_VADDR_KERNEL_START, (intptr_t)(&_rodata_end) - 1, MMU_PGSIZE_COARSE); /* Kernel rw data region */ mmu_region_kdata.vaddr = (intptr_t)(&_data_start); mmu_region_kdata.num_pages = MMU_PAGE_CNT_BY_RANGE( (intptr_t)(&_data_start), MMU_VADDR_KERNEL_END, MMU_PGSIZE_COARSE); mmu_region_kdata.paddr = (intptr_t)(&_data_start); /* Fill page tables with translations & attributes */ { #if configDEBUG >= KERROR_DEBUG char buf[80]; const char str_type[2][9] = {"sections", "pages"}; #define PRINTMAPREG(region) \ ksprintf(buf, sizeof(buf), "Mapped %s: %u %s", \ #region, region.num_pages, \ (region.pt->type == MMU_PTT_MASTER) ? \ str_type[0] : str_type[1]); \ KERROR(KERROR_DEBUG, buf); #else #define PRINTMAPREG(region) #endif #define MAP_REGION(reg) \ mmu_map_region(®); \ PRINTMAPREG(reg) //MAP_REGION(mmu_region_tkstack); MAP_REGION(mmu_region_kstack); MAP_REGION(mmu_region_kernel); MAP_REGION(mmu_region_kdata); MAP_REGION(mmu_region_page_tables); MAP_REGION(mmu_region_rpihw); #undef MAP_REGION #undef PRINTMAPREG } /* Copy system page table to vm version of it, this is the only easy way to * solve some issues now. TODO Maybe we'd like to do some major refactoring * some day. */ vm_pagetable_system.pt = mmu_pagetable_system; vm_pagetable_system.linkcount = 1; /* Activate page tables */ mmu_attach_pagetable(&mmu_pagetable_master); /* Load L1 TTB */ #if configDEBUG >= KERROR_DEBUG KERROR(KERROR_DEBUG, "Attached TTB mmu_pagetable_master"); #endif mmu_attach_pagetable(&mmu_pagetable_system); /* Add L2 pte into L1 mpt */ #if configDEBUG >= KERROR_DEBUG KERROR(KERROR_DEBUG, "Attached mmu_pagetable_system"); #endif SUBSYS_INITFINI("ptmapper OK"); }
/** * Create a inode. * @param fpath won't be duplicated. * @param oflags O_CREAT, O_DIRECTORY, O_RDONLY, O_WRONLY and O_RDWR * currently supported. * O_WRONLY/O_RDWR creates in write mode if possible, so this * should be always verified with stat. */ static int create_inode(struct fatfs_inode ** result, struct fatfs_sb * sb, char * fpath, long vn_hash, int oflags) { struct fatfs_inode * in = NULL; FILINFO fno; vnode_t * vn; vnode_t * xvp; mode_t vn_mode; ino_t inum; int err = 0, retval = 0; #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "create_inode(fpath \"%s\", vn_hash %u)\n", fpath, (uint32_t)vn_hash); #endif in = kzalloc(sizeof(struct fatfs_inode)); if (!in) { retval = -ENOMEM; goto fail; } in->in_fpath = fpath; vn = &in->in_vnode; in->open_count = ATOMIC_INIT(0); memset(&fno, 0, sizeof(fno)); if (oflags & O_DIRECTORY) { /* O_DIRECTORY was specified. */ /* TODO Maybe get mp stat? */ fno.fattrib = AM_DIR; } else if (oflags & O_CREAT) { if (sb->sb.mode_flags & MNT_RDONLY) return -EROFS; } else { err = f_stat(&sb->ff_fs, fpath, &fno); if (err) { retval = fresult2errno(err); goto fail; } } /* Try open */ if (fno.fattrib & AM_DIR) { /* it's a directory */ vn_mode = S_IFDIR; err = f_opendir(&in->dp, &sb->ff_fs, in->in_fpath); if (err) { #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "Can't open a dir (err: %d)\n", err); #endif retval = fresult2errno(err); goto fail; } inum = in->dp.ino; } else { /* it's a file */ unsigned char fomode = 0; fomode |= (oflags & O_CREAT) ? FA_OPEN_ALWAYS : FA_OPEN_EXISTING; /* The kernel should always have RW if possible. */ if (sb->sb.mode_flags & MNT_RDONLY) { fomode |= FA_READ; } else { fomode |= FA_READ | FA_WRITE; } vn_mode = S_IFREG; err = f_open(&in->fp, &sb->ff_fs, in->in_fpath, fomode); if (err) { #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "Can't open a file (err: %d)\n", err); #endif retval = fresult2errno(err); goto fail; } inum = in->fp.ino; } #ifdef configFATFS_DEBUG if (oflags & O_CREAT) KERROR(KERROR_DEBUG, "ff: Create & open ok\n"); else KERROR(KERROR_DEBUG, "ff: Open ok\n"); #endif init_fatfs_vnode(vn, inum, vn_mode, vn_hash, &(sb->sb)); /* Insert to the cache */ err = vfs_hash_insert(vn, vn_hash, &xvp, fatfs_vncmp, fpath); if (err) { retval = -ENOMEM; goto fail; } if (xvp) { /* TODO No idea what to do now */ KERROR(KERROR_WARN, "create_inode(): Found it during insert: \"%s\"\n", fpath); } #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "create_inode(): ok\n"); #endif *result = in; vrefset(vn, 1); /* Make ref for the caller. */ return 0; fail: #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "create_inode(): retval %i\n", retval); #endif kfree(in); return retval; }
/** * Mount a new fatfs. * @param mode mount flags. * @param param contains optional mount parameters. * @param parm_len length of param string. * @param[out] sb Returns the superblock of the new mount. * @return error code, -errno. */ static int fatfs_mount(const char * source, uint32_t mode, const char * parm, int parm_len, struct fs_superblock ** sb) { static dev_t fatfs_vdev_minor; struct fatfs_sb * fatfs_sb = NULL; vnode_t * vndev; char pdrv; int err, retval = 0; /* Get device vnode */ err = lookup_vnode(&vndev, curproc->croot, source, 0); if (err) { #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "fatfs source not found\n"); #endif return err; } if (!S_ISBLK(vndev->vn_mode)) return -ENOTBLK; /* Allocate superblock */ fatfs_sb = kzalloc(sizeof(struct fatfs_sb)); if (!fatfs_sb) return -ENOMEM; fs_fildes_set(&fatfs_sb->ff_devfile, vndev, O_RDWR); fatfs_sb->sb.vdev_id = DEV_MMTODEV(VDEV_MJNR_FATFS, fatfs_vdev_minor++); /* Insert sb to fatfs_sb_arr lookup array */ fatfs_sb_arr[DEV_MINOR(fatfs_sb->sb.vdev_id)] = fatfs_sb; /* Mount */ pdrv = (char)DEV_MINOR(fatfs_sb->sb.vdev_id); err = f_mount(&fatfs_sb->ff_fs, 0); if (err) { #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "Can't init a work area for FAT (%d)\n", err); #endif retval = fresult2errno(err); goto fail; } #ifdef configFATFS_DEBUG KERROR(KERROR_DEBUG, "Initialized a work area for FAT\n"); #endif #if (_FS_NOFSINFO == 0) /* Commit full scan of free clusters */ DWORD nclst; f_getfree(&fatfs_sb->ff_fs, &nclst); #endif /* Init super block */ fs_init_superblock(&fatfs_sb->sb, &fatfs_fs); /* TODO Detect if target dev is rdonly */ fatfs_sb->sb.mode_flags = mode; fatfs_sb->sb.root = create_root(fatfs_sb); fatfs_sb->sb.sb_dev = vndev; fatfs_sb->sb.sb_hashseed = fatfs_sb->sb.vdev_id; /* Function pointers to superblock methods */ fatfs_sb->sb.get_vnode = NULL; /* Not implemented for FAT. */ fatfs_sb->sb.delete_vnode = fatfs_delete_vnode; fatfs_sb->sb.umount = NULL; if (!fatfs_sb->sb.root) { KERROR(KERROR_ERR, "Root of fatfs not found\n"); return -EIO; } fs_insert_superblock(&fatfs_fs, &fatfs_sb->sb); fail: if (retval) { fatfs_sb_arr[DEV_MINOR(fatfs_sb->sb.vdev_id)] = NULL; kfree(fatfs_sb); } *sb = &fatfs_sb->sb; return retval; }
static void fb_mm_free_callback(struct kobj * obj) { struct buf * bp = containerof(obj, struct buf, b_obj); KERROR(KERROR_ERR, "FB buf object (%p) freed!\n", bp); }