|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2006 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stdint.h> ! 22: #include <string.h> ! 23: #include <errno.h> ! 24: #include <assert.h> ! 25: #include <ipxe/nvs.h> ! 26: ! 27: /** @file ! 28: * ! 29: * Non-volatile storage ! 30: * ! 31: */ ! 32: ! 33: /** ! 34: * Calculate length up to next block boundary ! 35: * ! 36: * @v nvs NVS device ! 37: * @v address Starting address ! 38: * @v max_len Maximum length ! 39: * @ret len Length to use, stopping at block boundaries ! 40: */ ! 41: static size_t nvs_frag_len ( struct nvs_device *nvs, unsigned int address, ! 42: size_t max_len ) { ! 43: size_t frag_len; ! 44: ! 45: /* If there are no block boundaries, return the maximum length */ ! 46: if ( ! nvs->block_size ) ! 47: return max_len; ! 48: ! 49: /* Calculate space remaining up to next block boundary */ ! 50: frag_len = ( ( nvs->block_size - ! 51: ( address & ( nvs->block_size - 1 ) ) ) ! 52: << nvs->word_len_log2 ); ! 53: ! 54: /* Limit to maximum length */ ! 55: if ( max_len < frag_len ) ! 56: return max_len; ! 57: ! 58: return frag_len; ! 59: } ! 60: ! 61: /** ! 62: * Read from non-volatile storage device ! 63: * ! 64: * @v nvs NVS device ! 65: * @v address Address from which to read ! 66: * @v data Data buffer ! 67: * @v len Length of data buffer ! 68: * @ret rc Return status code ! 69: */ ! 70: int nvs_read ( struct nvs_device *nvs, unsigned int address, ! 71: void *data, size_t len ) { ! 72: size_t frag_len; ! 73: int rc; ! 74: ! 75: /* We don't even attempt to handle buffer lengths that aren't ! 76: * an integral number of words. ! 77: */ ! 78: assert ( ( len & ( ( 1 << nvs->word_len_log2 ) - 1 ) ) == 0 ); ! 79: ! 80: while ( len ) { ! 81: ! 82: /* Calculate length to read, stopping at block boundaries */ ! 83: frag_len = nvs_frag_len ( nvs, address, len ); ! 84: ! 85: /* Read this portion of the buffer from the device */ ! 86: if ( ( rc = nvs->read ( nvs, address, data, frag_len ) ) != 0 ) ! 87: return rc; ! 88: ! 89: /* Update parameters */ ! 90: data += frag_len; ! 91: address += ( frag_len >> nvs->word_len_log2 ); ! 92: len -= frag_len; ! 93: } ! 94: ! 95: return 0; ! 96: } ! 97: ! 98: /** ! 99: * Verify content of non-volatile storage device ! 100: * ! 101: * @v nvs NVS device ! 102: * @v address Address from which to read ! 103: * @v data Data to compare against ! 104: * @v len Length of data buffer ! 105: * @ret rc Return status code ! 106: */ ! 107: static int nvs_verify ( struct nvs_device *nvs, unsigned int address, ! 108: const void *data, size_t len ) { ! 109: uint8_t read_data[len]; ! 110: int rc; ! 111: ! 112: /* Read data into temporary buffer */ ! 113: if ( ( rc = nvs_read ( nvs, address, read_data, len ) ) != 0 ) ! 114: return rc; ! 115: ! 116: /* Compare data */ ! 117: if ( memcmp ( data, read_data, len ) != 0 ) { ! 118: DBG ( "NVS %p verification failed at %#04x+%zd\n", ! 119: nvs, address, len ); ! 120: return -EIO; ! 121: } ! 122: ! 123: return 0; ! 124: } ! 125: ! 126: /** ! 127: * Write to non-volatile storage device ! 128: * ! 129: * @v nvs NVS device ! 130: * @v address Address to which to write ! 131: * @v data Data buffer ! 132: * @v len Length of data buffer ! 133: * @ret rc Return status code ! 134: */ ! 135: int nvs_write ( struct nvs_device *nvs, unsigned int address, ! 136: const void *data, size_t len ) { ! 137: size_t frag_len; ! 138: int rc; ! 139: ! 140: /* We don't even attempt to handle buffer lengths that aren't ! 141: * an integral number of words. ! 142: */ ! 143: assert ( ( len & ( ( 1 << nvs->word_len_log2 ) - 1 ) ) == 0 ); ! 144: ! 145: while ( len ) { ! 146: ! 147: /* Calculate length to write, stopping at block boundaries */ ! 148: frag_len = nvs_frag_len ( nvs, address, len ); ! 149: ! 150: /* Write this portion of the buffer to the device */ ! 151: if ( ( rc = nvs->write ( nvs, address, data, frag_len ) ) != 0) ! 152: return rc; ! 153: ! 154: /* Read back and verify data */ ! 155: if ( ( rc = nvs_verify ( nvs, address, data, frag_len ) ) != 0) ! 156: return rc; ! 157: ! 158: /* Update parameters */ ! 159: data += frag_len; ! 160: address += ( frag_len >> nvs->word_len_log2 ); ! 161: len -= frag_len; ! 162: } ! 163: ! 164: return 0; ! 165: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.