nvs.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdint.h>
00022 #include <string.h>
00023 #include <errno.h>
00024 #include <assert.h>
00025 #include <gpxe/nvs.h>
00026 
00027 /** @file
00028  *
00029  * Non-volatile storage
00030  *
00031  */
00032 
00033 /**
00034  * Read from non-volatile storage device
00035  *
00036  * @v nvs               NVS device
00037  * @v address           Address from which to read
00038  * @v data              Data buffer
00039  * @v len               Length of data buffer
00040  * @ret rc              Return status code
00041  */
00042 int nvs_read ( struct nvs_device *nvs, unsigned int address,
00043                void *data, size_t len ) {
00044         size_t frag_len;
00045         int rc;
00046 
00047         /* We don't even attempt to handle buffer lengths that aren't
00048          * an integral number of words.
00049          */
00050         assert ( ( len & ( ( 1 << nvs->word_len_log2 ) - 1 ) ) == 0 );
00051 
00052         while ( len ) {
00053 
00054                 /* Calculate space remaining up to next block boundary */
00055                 frag_len = ( ( nvs->block_size -
00056                                ( address & ( nvs->block_size - 1 ) ) )
00057                              << nvs->word_len_log2 );
00058 
00059                 /* Limit to space remaining in buffer */
00060                 if ( frag_len > len )
00061                         frag_len = len;
00062 
00063                 /* Read this portion of the buffer from the device */
00064                 if ( ( rc = nvs->read ( nvs, address, data, frag_len ) ) != 0 )
00065                         return rc;
00066 
00067                 /* Update parameters */
00068                 data += frag_len;
00069                 address += ( frag_len >> nvs->word_len_log2 );
00070                 len -= frag_len;
00071         }
00072 
00073         return 0;
00074 }
00075 
00076 /**
00077  * Verify content of non-volatile storage device
00078  *
00079  * @v nvs               NVS device
00080  * @v address           Address from which to read
00081  * @v data              Data to compare against
00082  * @v len               Length of data buffer
00083  * @ret rc              Return status code
00084  */
00085 static int nvs_verify ( struct nvs_device *nvs, unsigned int address,
00086                         const void *data, size_t len ) {
00087         uint8_t read_data[len];
00088         int rc;
00089 
00090         /* Read data into temporary buffer */
00091         if ( ( rc = nvs_read ( nvs, address, read_data, len ) ) != 0 )
00092                 return rc;
00093 
00094         /* Compare data */
00095         if ( memcmp ( data, read_data, len ) != 0 ) {
00096                 DBG ( "NVS %p verification failed at %#04x+%zd\n",
00097                       nvs, address, len );
00098                 return -EIO;
00099         }
00100 
00101         return 0;
00102 }
00103 
00104 /**
00105  * Write to non-volatile storage device
00106  *
00107  * @v nvs               NVS device
00108  * @v address           Address to which to write
00109  * @v data              Data buffer
00110  * @v len               Length of data buffer
00111  * @ret rc              Return status code
00112  */
00113 int nvs_write ( struct nvs_device *nvs, unsigned int address,
00114                 const void *data, size_t len ) {
00115         size_t frag_len;
00116         int rc;
00117 
00118         /* We don't even attempt to handle buffer lengths that aren't
00119          * an integral number of words.
00120          */
00121         assert ( ( len & ( ( 1 << nvs->word_len_log2 ) - 1 ) ) == 0 );
00122 
00123         while ( len ) {
00124 
00125                 /* Calculate space remaining up to next block boundary */
00126                 frag_len = ( ( nvs->block_size -
00127                                ( address & ( nvs->block_size - 1 ) ) )
00128                              << nvs->word_len_log2 );
00129 
00130                 /* Limit to space remaining in buffer */
00131                 if ( frag_len > len )
00132                         frag_len = len;
00133 
00134                 /* Write this portion of the buffer to the device */
00135                 if ( ( rc = nvs->write ( nvs, address, data, frag_len ) ) != 0)
00136                         return rc;
00137 
00138                 /* Read back and verify data */
00139                 if ( ( rc = nvs_verify ( nvs, address, data, frag_len ) ) != 0)
00140                         return rc;
00141 
00142                 /* Update parameters */
00143                 data += frag_len;
00144                 address += ( frag_len >> nvs->word_len_log2 );
00145                 len -= frag_len;
00146         }
00147 
00148         return 0;
00149 }

Generated on Tue Apr 6 20:01:06 2010 for gPXE by  doxygen 1.5.7.1