/* * fatfs.c - FATFS file system API implementation. * * Author Mohamed Lamine Karaoui (2015) * Alain Greiner (2016) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // FATFS specific functions : these functions cannot be called by the VFS ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// inline uint32_t fatfs_lba_from_cluster( fatfs_ctx_t * ctx, uint32_t cluster ) { return (ctx->cluster_begin_lba + ((cluster - 2) * ctx->sectors_per_cluster)); } ///////////////////////////////////////////// error_t fatfs_get_cluster( mapper_t * mapper, uint32_t first_cluster, uint32_t searched_page, uint32_t * cluster ) { page_t * current_page_desc; // pointer on current page descriptor uint32_t * current_page_buffer; // pointer on current page (array of uint32_t) uint32_t current_page_index; // index of current page in mapper uint32_t current_page_offset; // offset of slot in current page uint32_t page_count_in_file; // index of page in file (index in linked list) uint32_t current_cluster; // content of current FAT slot // compute number of FAT slots per PPM page uint32_t slots_per_page = CONFIG_PPM_PAGE_SIZE >> 2; // initialize loop variable current_page_index = first_cluster / slots_per_page; current_page_offset = first_cluster % slots_per_page; page_count_in_file = 0; // scan FAT (i.e. traverse FAT linked list) while( page_count_in_file <= searched_page ) { // get pointer on current page descriptor current_page_desc = mapper_get_page( mapper , current_page_index ); if( current_page_desc == NULL ) return EIO; // get pointer on buffer for current page current_page_buffer = (uint32_t *)ppm_page2base( current_page_desc ); // get FAT slot content current_cluster = current_page_buffer[current_page_offset]; // update loop variables current_page_index = current_cluster / slots_per_page; current_page_offset = current_cluster % slots_per_page; page_count_in_file++; } // return success *cluster = current_cluster; return 0; } // end fatfs_get_cluster() //////////////////////////////////////////////////////////////////////////////////////// // This function returns the FATFS cluster index of a page identified by its page // index in the file, using the FAT mapper. It scans the FAT mapper, starting from the // FATFS cluster index allocated to the first page of the file, until it reaches the // searched page. The FAT mapper is automatically updated in case of miss. // This function can be called by any thread running in any cluster, as it uses the // RPC_FATFS_GET_CLUSTER to access the remote FAT mapper if required. // We use a RPC to scan the FAT because the RPC_FIFO will avoid contention // in the cluster containing the FAT mapper, and the RPC latency is not critical // compared to the device access latency. //////////////////////////////////////////////////////////////////////////////////////// // @ ctx : pointer on local FATFS context. // @ first_cluster : first cluster allocated to a file in FATFS. // @ page_index : index of searched page in file (one page occupies one cluster). // @ cluster_index : [out] pointer on buffer for FATFS cluster index. // @ return 0 if success / return EIO if a FAT cluster miss cannot be solved. //////////////////////////////////////////////////////////////////////////////////////// static error_t fatfs_cluster_from_index( fatfs_ctx_t * ctx, uint32_t first_cluster, uint32_t page_index, uint32_t * cluster_index ) { uint32_t searched_cluster; // searched FATFS cluster index error_t error; // get extended pointer on FAT mapper xptr_t fat_mapper_xp = ctx->fat_mapper_xp; // get cluster cxy and local pointer on FAT mapper cxy_t fat_mapper_cxy = GET_CXY( fat_mapper_xp ); mapper_t * fat_mapper_ptr = (mapper_t *)GET_PTR( fat_mapper_xp ); if( fat_mapper_cxy == local_cxy ) // FAT mapper is local { error = fatfs_get_cluster( fat_mapper_ptr, first_cluster, page_index, &searched_cluster ); } else // FAT mapper is remote { rpc_fatfs_get_cluster_client( fat_mapper_cxy, fat_mapper_ptr, first_cluster, page_index, &searched_cluster, &error ); } if( error ) { printk("\n[ERROR] in %s : cannot access FAT\n", __FUNCTION__ ); return error; } // return success *cluster_index = searched_cluster; return 0; } // end fatfs_cluster_from_index() /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // Generic API : the following functions are called by the VFS, // and must be defined by all isupported file systems. /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// error_t fatfs_inode_create( struct vfs_inode_s * vfs_inode ) { printk("\n[PANIC] %s not fully implemented yet\n", __FUNCTION__ ); hal_core_sleep(); kmem_req_t req; fatfs_inode_t * fatfs_inode; // allocate memory for fatfs inode req.type = KMEM_FATFS_INODE; req.size = sizeof(fatfs_inode_t); req.flags = AF_KERNEL | AF_ZERO; fatfs_inode = (fatfs_inode_t *)kmem_alloc( &req ); if( fatfs_inode == NULL ) return ENOMEM; // initialise ramfs_inode fatfs_inode->first_cluster = 0; // TODO ??? fatfs_inode->ctx = (fatfs_ctx_t *)vfs_inode->ctx->extend; // link fatfs_inode to vfs_inode vfs_inode->extend = fatfs_inode; return 0; } ////////////////////////////////////////////////////// void fatfs_inode_destroy( struct vfs_inode_s * inode ) { printk("\n[PANIC] %s not fully implemented yet\n", __FUNCTION__ ); hal_core_sleep(); } ////////////////////////////////////////////////// error_t fatfs_ctx_create( struct vfs_ctx_s * ctx ) { printk("\n[PANIC] %s not fully implemented yet\n", __FUNCTION__ ); hal_core_sleep(); return 0; } //////////////////////////////////////////////// void fatfs_ctx_destroy( struct vfs_ctx_s * ctx ) { printk("\n[PANIC] %s not fully implemented yet\n", __FUNCTION__ ); hal_core_sleep(); } //////////////////////////////////////////////// static error_t fatfs_access_page( page_t * page, bool_t is_read ) { // get source buffer base address char * buffer = (char *)ppm_page2base( page ); // get pointer on source mapper and page index from page descriptor mapper_t * src_mapper = page->mapper; uint32_t page_index = page->index; if( src_mapper == NULL) { printk("\n[PANIC] in %s : no mapper for this page\n", __FUNCTION__ ); hal_core_sleep(); } // get VFS inode pointer from mapper vfs_inode_t * vfs_inode = src_mapper->inode; // get FATFS inode pointer for VFS inode fatfs_inode_t * fatfs_inode = (fatfs_inode_t *)vfs_inode->extend; // get first cluster index from FATFS inode uint32_t first_cluster = fatfs_inode->first_cluster; // get FATFS context pointer from FATFS inode fatfs_ctx_t * fatfs_ctx = fatfs_inode->ctx; // get number of sectors uint32_t count = fatfs_ctx->sectors_per_cluster; // compute FATFS_cluster index for the accessed page uint32_t cluster = 0; error_t error = fatfs_cluster_from_index( fatfs_ctx, first_cluster, page_index, &cluster ); if( error ) return EIO; // get lba from cluster uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , cluster ); // access device if( is_read ) error = dev_ioc_read ( buffer , lba , count ); else error = dev_ioc_write( buffer , lba , count ); if( error ) { printk("\n[ERROR] in %s : cannot access IOC device\n", __FUNCTION__ ); return error; } // successful access return 0; } //////////////////////////////////////////////// error_t fatfs_write_page( struct page_s * page ) { bool_t is_read = false; return fatfs_access_page( page , is_read ); } /////////////////////////////////////////////// error_t fatfs_read_page( struct page_s * page ) { bool_t is_read = true; return fatfs_access_page( page , is_read ); }