Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / interface / vmware / guestinfo.c
1 /*
2  * Copyright (C) 2012 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 /** @file
23  *
24  * VMware GuestInfo settings
25  *
26  */
27
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <ipxe/init.h>
34 #include <ipxe/settings.h>
35 #include <ipxe/netdevice.h>
36 #include <ipxe/guestrpc.h>
37
38 /** GuestInfo GuestRPC channel */
39 static int guestinfo_channel;
40
41 /**
42  * Fetch value of typed GuestInfo setting
43  *
44  * @v settings          Settings block
45  * @v setting           Setting to fetch
46  * @v type              Setting type to attempt (or NULL for default)
47  * @v data              Buffer to fill with setting data
48  * @v len               Length of buffer
49  * @ret found           Setting found in GuestInfo
50  * @ret len             Length of setting data, or negative error
51  */
52 static int guestinfo_fetch_type ( struct settings *settings,
53                                   struct setting *setting,
54                                   const struct setting_type *type,
55                                   void *data, size_t len, int *found ) {
56         const char *parent_name = settings->parent->name;
57         char command[ 24 /* "info-get guestinfo.ipxe." */ +
58                       strlen ( parent_name ) + 1 /* "." */ +
59                       strlen ( setting->name ) + 1 /* "." */ +
60                       ( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ];
61         struct setting *predefined;
62         char *info;
63         int info_len;
64         int check_len;
65         int ret;
66
67         /* Construct info-get command */
68         snprintf ( command, sizeof ( command ),
69                    "info-get guestinfo.ipxe.%s%s%s%s%s",
70                    parent_name, ( parent_name[0] ? "." : "" ), setting->name,
71                    ( type ? "." : "" ), ( type ? type->name : "" ) );
72
73         /* Check for existence and obtain length of GuestInfo value */
74         info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 );
75         if ( info_len < 0 ) {
76                 ret = info_len;
77                 goto err_get_info_len;
78         }
79
80         /* Mark as found */
81         *found = 1;
82
83         /* Determine default type if necessary */
84         if ( ! type ) {
85                 predefined = find_setting ( setting->name );
86                 type = ( predefined ? predefined->type : &setting_type_string );
87         }
88         assert ( type != NULL );
89
90         /* Allocate temporary block to hold GuestInfo value */
91         info = zalloc ( info_len + 1 /* NUL */ );
92         if ( ! info ) {
93                 DBGC ( settings, "GuestInfo %p could not allocate %d bytes\n",
94                        settings, info_len );
95                 ret = -ENOMEM;
96                 goto err_alloc;
97         }
98         info[info_len] = '\0';
99
100         /* Fetch GuestInfo value */
101         check_len = guestrpc_command ( guestinfo_channel, command,
102                                        info, info_len );
103         if ( check_len < 0 ) {
104                 ret = check_len;
105                 goto err_get_info;
106         }
107         if ( check_len != info_len ) {
108                 DBGC ( settings, "GuestInfo %p length mismatch (expected %d, "
109                        "got %d)\n", settings, info_len, check_len );
110                 ret = -EIO;
111                 goto err_get_info;
112         }
113         DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n",
114                 settings, &command[9] /* Skip "info-get " */, info );
115
116         /* Parse GuestInfo value according to type */
117         ret = setting_parse ( type, info, data, len );
118         if ( ret < 0 ) {
119                 DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: "
120                        "%s\n", settings, info, type->name, strerror ( ret ) );
121                 goto err_parse;
122         }
123
124  err_parse:
125  err_get_info:
126         free ( info );
127  err_alloc:
128  err_get_info_len:
129         return ret;
130 }
131
132 /**
133  * Fetch value of GuestInfo setting
134  *
135  * @v settings          Settings block
136  * @v setting           Setting to fetch
137  * @v data              Buffer to fill with setting data
138  * @v len               Length of buffer
139  * @ret len             Length of setting data, or negative error
140  */
141 static int guestinfo_fetch ( struct settings *settings,
142                              struct setting *setting,
143                              void *data, size_t len ) {
144         struct setting_type *type;
145         int found = 0;
146         int ret;
147
148         /* Try default type first */
149         ret = guestinfo_fetch_type ( settings, setting, NULL,
150                                      data, len, &found );
151         if ( found )
152                 return ret;
153
154         /* Otherwise, try all possible types */
155         for_each_table_entry ( type, SETTING_TYPES ) {
156                 ret = guestinfo_fetch_type ( settings, setting, type,
157                                              data, len, &found );
158                 if ( found )
159                         return ret;
160         }
161
162         /* Not found */
163         return -ENOENT;
164 }
165
166 /** GuestInfo settings operations */
167 static struct settings_operations guestinfo_settings_operations = {
168         .fetch = guestinfo_fetch,
169 };
170
171 /** GuestInfo settings */
172 static struct settings guestinfo_settings = {
173         .refcnt = NULL,
174         .siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ),
175         .children = LIST_HEAD_INIT ( guestinfo_settings.children ),
176         .op = &guestinfo_settings_operations,
177 };
178
179 /** Initialise GuestInfo settings */
180 static void guestinfo_init ( void ) {
181         int rc;
182
183         /* Open GuestRPC channel */
184         guestinfo_channel = guestrpc_open();
185         if ( guestinfo_channel < 0 ) {
186                 rc = guestinfo_channel;
187                 DBG ( "GuestInfo could not open channel: %s\n",
188                       strerror ( rc ) );
189                 return;
190         }
191
192         /* Register root GuestInfo settings */
193         if ( ( rc = register_settings ( &guestinfo_settings, NULL,
194                                         "vmware" ) ) != 0 ) {
195                 DBG ( "GuestInfo could not register settings: %s\n",
196                       strerror ( rc ) );
197                 return;
198         }
199 }
200
201 /** GuestInfo settings initialiser */
202 struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
203         .initialise = guestinfo_init,
204 };
205
206 /**
207  * Create per-netdevice GuestInfo settings
208  *
209  * @v netdev            Network device
210  * @ret rc              Return status code
211  */
212 static int guestinfo_net_probe ( struct net_device *netdev ) {
213         struct settings *settings;
214         int rc;
215
216         /* Do nothing unless we have a GuestInfo channel available */
217         if ( guestinfo_channel < 0 )
218                 return 0;
219
220         /* Allocate and initialise settings block */
221         settings = zalloc ( sizeof ( *settings ) );
222         if ( ! settings ) {
223                 rc = -ENOMEM;
224                 goto err_alloc;
225         }
226         settings_init ( settings, &guestinfo_settings_operations, NULL, NULL );
227
228         /* Register settings */
229         if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
230                                         "vmware" ) ) != 0 ) {
231                 DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
232                        settings, netdev->name, strerror ( rc ) );
233                 goto err_register;
234         }
235         DBGC ( settings, "GuestInfo %p registered for %s\n",
236                settings, netdev->name );
237
238         return 0;
239
240  err_register:
241         free ( settings );
242  err_alloc:
243         return rc;
244 }
245
246 /**
247  * Remove per-netdevice GuestInfo settings
248  *
249  * @v netdev            Network device
250  */
251 static void guestinfo_net_remove ( struct net_device *netdev ) {
252         struct settings *parent = netdev_settings ( netdev );
253         struct settings *settings;
254
255         list_for_each_entry ( settings, &parent->children, siblings ) {
256                 if ( settings->op == &guestinfo_settings_operations ) {
257                         DBGC ( settings, "GuestInfo %p unregistered for %s\n",
258                                settings, netdev->name );
259                         unregister_settings ( settings );
260                         free ( settings );
261                         return;
262                 }
263         }
264 }
265
266 /** GuestInfo per-netdevice driver */
267 struct net_driver guestinfo_net_driver __net_driver = {
268         .name = "GuestInfo",
269         .probe = guestinfo_net_probe,
270         .remove = guestinfo_net_remove,
271 };