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