Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / nvo.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <ipxe/dhcp.h>
27 #include <ipxe/nvs.h>
28 #include <ipxe/nvo.h>
29
30 /** @file
31  *
32  * Non-volatile stored options
33  *
34  */
35
36 /**
37  * Calculate checksum over non-volatile stored options
38  *
39  * @v nvo               Non-volatile options block
40  * @ret sum             Checksum
41  */
42 static unsigned int nvo_checksum ( struct nvo_block *nvo ) {
43         uint8_t *data = nvo->data;
44         uint8_t sum = 0;
45         unsigned int i;
46
47         for ( i = 0 ; i < nvo->len ; i++ ) {
48                 sum += *(data++);
49         }
50         return sum;
51 }
52
53 /**
54  * Reallocate non-volatile stored options block
55  *
56  * @v nvo               Non-volatile options block
57  * @v len               New length
58  * @ret rc              Return status code
59  */
60 static int nvo_realloc ( struct nvo_block *nvo, size_t len ) {
61         void *new_data;
62
63         /* Reallocate data */
64         new_data = realloc ( nvo->data, len );
65         if ( ! new_data ) {
66                 DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
67                        nvo, len );
68                 return -ENOMEM;
69         }
70         nvo->data = new_data;
71         nvo->len = len;
72
73         /* Update DHCP option block */
74         if ( len ) {
75                 nvo->dhcpopts.data = ( nvo->data + 1 /* checksum */ );
76                 nvo->dhcpopts.alloc_len = ( len - 1 /* checksum */ );
77         } else {
78                 nvo->dhcpopts.data = NULL;
79                 nvo->dhcpopts.used_len = 0;
80                 nvo->dhcpopts.alloc_len = 0;
81         }
82
83         return 0;
84 }
85
86 /**
87  * Reallocate non-volatile stored options DHCP option block
88  *
89  * @v options           DHCP option block
90  * @v len               New length
91  * @ret rc              Return status code
92  */
93 static int nvo_realloc_dhcpopt ( struct dhcp_options *options, size_t len ) {
94         struct nvo_block *nvo =
95                 container_of ( options, struct nvo_block, dhcpopts );
96         int rc;
97
98         /* Refuse to reallocate if we have no way to resize the block */
99         if ( ! nvo->resize )
100                 return dhcpopt_no_realloc ( options, len );
101
102         /* Allow one byte for the checksum (if any data is present) */
103         if ( len )
104                 len += 1;
105
106         /* Resize underlying non-volatile options block */
107         if ( ( rc = nvo->resize ( nvo, len ) ) != 0 ) {
108                 DBGC ( nvo, "NVO %p could not resize to %zd bytes: %s\n",
109                        nvo, len, strerror ( rc ) );
110                 return rc;
111         }
112
113         /* Reallocate in-memory options block */
114         if ( ( rc = nvo_realloc ( nvo, len ) ) != 0 )
115                 return rc;
116
117         return 0;
118 }
119
120 /**
121  * Load non-volatile stored options from non-volatile storage device
122  *
123  * @v nvo               Non-volatile options block
124  * @ret rc              Return status code
125  */
126 static int nvo_load ( struct nvo_block *nvo ) {
127         uint8_t *options_data = nvo->dhcpopts.data;
128         int rc;
129
130         /* Skip reading zero-length NVO fields */
131         if ( nvo->len == 0 ) {
132                 DBGC ( nvo, "NVO %p is empty; skipping load\n", nvo );
133                 return 0;
134         }
135
136         /* Read data */
137         if ( ( rc = nvs_read ( nvo->nvs, nvo->address, nvo->data,
138                                nvo->len ) ) != 0 ) {
139                 DBGC ( nvo, "NVO %p could not read %zd bytes at %#04x: %s\n",
140                        nvo, nvo->len, nvo->address, strerror ( rc ) );
141                 return rc;
142         }
143
144         /* If checksum fails, or options data starts with a zero,
145          * assume the whole block is invalid.  This should capture the
146          * case of random initial contents.
147          */
148         if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) {
149                 DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; "
150                        "assuming empty\n", nvo, nvo_checksum ( nvo ),
151                        options_data[0] );
152                 memset ( nvo->data, 0, nvo->len );
153         }
154
155         /* Rescan DHCP option block */
156         dhcpopt_update_used_len ( &nvo->dhcpopts );
157
158         DBGC ( nvo, "NVO %p loaded from non-volatile storage\n", nvo );
159         return 0;
160 }
161
162 /**
163  * Save non-volatile stored options back to non-volatile storage device
164  *
165  * @v nvo               Non-volatile options block
166  * @ret rc              Return status code
167  */
168 static int nvo_save ( struct nvo_block *nvo ) {
169         uint8_t *checksum = nvo->data;
170         int rc;
171
172         /* Recalculate checksum, if applicable */
173         if ( nvo->len > 0 )
174                 *checksum -= nvo_checksum ( nvo );
175
176         /* Write data */
177         if ( ( rc = nvs_write ( nvo->nvs, nvo->address, nvo->data,
178                                 nvo->len ) ) != 0 ) {
179                 DBGC ( nvo, "NVO %p could not write %zd bytes at %#04x: %s\n",
180                        nvo, nvo->len, nvo->address, strerror ( rc ) );
181                 return rc;
182         }
183
184         DBGC ( nvo, "NVO %p saved to non-volatile storage\n", nvo );
185         return 0;
186 }
187
188 /**
189  * Check applicability of NVO setting
190  *
191  * @v settings          Settings block
192  * @v setting           Setting
193  * @ret applies         Setting applies within this settings block
194  */
195 int nvo_applies ( struct settings *settings __unused,
196                   const struct setting *setting ) {
197
198         return ( ( setting->scope == NULL ) &&
199                  dhcpopt_applies ( setting->tag ) );
200 }
201
202 /**
203  * Store value of NVO setting
204  *
205  * @v settings          Settings block
206  * @v setting           Setting to store
207  * @v data              Setting data, or NULL to clear setting
208  * @v len               Length of setting data
209  * @ret rc              Return status code
210  */
211 static int nvo_store ( struct settings *settings, const struct setting *setting,
212                        const void *data, size_t len ) {
213         struct nvo_block *nvo =
214                 container_of ( settings, struct nvo_block, settings );
215         int rc;
216
217         /* Update stored options */
218         if ( ( rc = dhcpopt_store ( &nvo->dhcpopts, setting->tag,
219                                     data, len ) ) != 0 ) {
220                 DBGC ( nvo, "NVO %p could not store %zd bytes: %s\n",
221                        nvo, len, strerror ( rc ) );
222                 return rc;
223         }
224
225         /* Save updated options to NVS */
226         if ( ( rc = nvo_save ( nvo ) ) != 0 )
227                 return rc;
228
229         return 0;
230 }
231
232 /**
233  * Fetch value of NVO setting
234  *
235  * @v settings          Settings block
236  * @v setting           Setting to fetch
237  * @v data              Buffer to fill with setting data
238  * @v len               Length of buffer
239  * @ret len             Length of setting data, or negative error
240  *
241  * The actual length of the setting will be returned even if
242  * the buffer was too small.
243  */
244 static int nvo_fetch ( struct settings *settings, struct setting *setting,
245                        void *data, size_t len ) {
246         struct nvo_block *nvo =
247                 container_of ( settings, struct nvo_block, settings );
248
249         return dhcpopt_fetch ( &nvo->dhcpopts, setting->tag, data, len );
250 }
251
252 /** NVO settings operations */
253 static struct settings_operations nvo_settings_operations = {
254         .applies = nvo_applies,
255         .store = nvo_store,
256         .fetch = nvo_fetch,
257 };
258
259 /**
260  * Initialise non-volatile stored options
261  *
262  * @v nvo               Non-volatile options block
263  * @v nvs               Underlying non-volatile storage device
264  * @v address           Address within NVS device
265  * @v len               Length of non-volatile options data
266  * @v resize            Resize method
267  * @v refcnt            Containing object reference counter, or NULL
268  */
269 void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
270                 size_t address, size_t len,
271                 int ( * resize ) ( struct nvo_block *nvo, size_t len ),
272                 struct refcnt *refcnt ) {
273         nvo->nvs = nvs;
274         nvo->address = address;
275         nvo->len = len;
276         nvo->resize = resize;
277         dhcpopt_init ( &nvo->dhcpopts, NULL, 0, nvo_realloc_dhcpopt );
278         settings_init ( &nvo->settings, &nvo_settings_operations,
279                         refcnt, NULL );
280 }
281
282 /**
283  * Register non-volatile stored options
284  *
285  * @v nvo               Non-volatile options block
286  * @v parent            Parent settings block, or NULL
287  * @ret rc              Return status code
288  */
289 int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
290         int rc;
291
292         /* Allocate memory for options */
293         if ( ( rc = nvo_realloc ( nvo, nvo->len ) ) != 0 )
294                 goto err_realloc;
295
296         /* Read data from NVS */
297         if ( ( rc = nvo_load ( nvo ) ) != 0 )
298                 goto err_load;
299
300         /* Register settings */
301         if ( ( rc = register_settings ( &nvo->settings, parent,
302                                         NVO_SETTINGS_NAME ) ) != 0 )
303                 goto err_register;
304
305         DBGC ( nvo, "NVO %p registered\n", nvo );
306         return 0;
307         
308  err_register:
309  err_load:
310         nvo_realloc ( nvo, 0 );
311  err_realloc:
312         return rc;
313 }
314
315 /**
316  * Unregister non-volatile stored options
317  *
318  * @v nvo               Non-volatile options block
319  */
320 void unregister_nvo ( struct nvo_block *nvo ) {
321         unregister_settings ( &nvo->settings );
322         nvo_realloc ( nvo, 0 );
323         DBGC ( nvo, "NVO %p unregistered\n", nvo );
324 }