|
|
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.