~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/interface/efi/efi_snp_hii.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * 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
/**
 
27
 * @file
 
28
 *
 
29
 * EFI SNP HII protocol
 
30
 *
 
31
 * The HII protocols are some of the less-well designed parts of the
 
32
 * entire EFI specification.  This is a significant accomplishment.
 
33
 *
 
34
 * The face-slappingly ludicrous query string syntax seems to be
 
35
 * motivated by the desire to allow a caller to query multiple drivers
 
36
 * simultaneously via the single-instance HII_CONFIG_ROUTING_PROTOCOL,
 
37
 * which is supposed to pass relevant subsets of the query string to
 
38
 * the relevant drivers.
 
39
 *
 
40
 * Nobody uses the HII_CONFIG_ROUTING_PROTOCOL.  Not even the EFI
 
41
 * setup browser uses the HII_CONFIG_ROUTING_PROTOCOL.  To the best of
 
42
 * my knowledge, there has only ever been one implementation of the
 
43
 * HII_CONFIG_ROUTING_PROTOCOL (as part of EDK2), and it just doesn't
 
44
 * work.  It's so badly broken that I can't even figure out what the
 
45
 * code is _trying_ to do.
 
46
 *
 
47
 * Fundamentally, the problem seems to be that Javascript programmers
 
48
 * should not be allowed to design APIs for C code.
 
49
 */
 
50
 
 
51
#include <string.h>
 
52
#include <strings.h>
 
53
#include <stdlib.h>
 
54
#include <stdio.h>
 
55
#include <wchar.h>
 
56
#include <errno.h>
 
57
#include <ipxe/settings.h>
 
58
#include <ipxe/nvo.h>
 
59
#include <ipxe/device.h>
 
60
#include <ipxe/netdevice.h>
 
61
#include <ipxe/version.h>
 
62
#include <ipxe/efi/efi.h>
 
63
#include <ipxe/efi/efi_hii.h>
 
64
#include <ipxe/efi/efi_snp.h>
 
65
#include <ipxe/efi/efi_strings.h>
 
66
#include <ipxe/efi/efi_utils.h>
 
67
#include <config/branding.h>
 
68
 
 
69
/** EFI platform setup formset GUID */
 
70
static EFI_GUID efi_hii_platform_setup_formset_guid
 
71
        = EFI_HII_PLATFORM_SETUP_FORMSET_GUID;
 
72
 
 
73
/** EFI IBM UCM compliant formset GUID */
 
74
static EFI_GUID efi_hii_ibm_ucm_compliant_formset_guid
 
75
        = EFI_HII_IBM_UCM_COMPLIANT_FORMSET_GUID;
 
76
 
 
77
/** EFI HII database protocol */
 
78
static EFI_HII_DATABASE_PROTOCOL *efihii;
 
79
EFI_REQUEST_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii );
 
80
 
 
81
/**
 
82
 * Identify settings to be exposed via HII
 
83
 *
 
84
 * @v snpdev            SNP device
 
85
 * @ret settings        Settings, or NULL
 
86
 */
 
87
static struct settings * efi_snp_hii_settings ( struct efi_snp_device *snpdev ){
 
88
 
 
89
        return find_child_settings ( netdev_settings ( snpdev->netdev ),
 
90
                                     NVO_SETTINGS_NAME );
 
91
}
 
92
 
 
93
/**
 
94
 * Check whether or not setting is applicable
 
95
 *
 
96
 * @v snpdev            SNP device
 
97
 * @v setting           Setting
 
98
 * @ret applies         Setting applies
 
99
 */
 
100
static int efi_snp_hii_setting_applies ( struct efi_snp_device *snpdev,
 
101
                                         struct setting *setting ) {
 
102
 
 
103
        return nvo_applies ( efi_snp_hii_settings ( snpdev ), setting );
 
104
}
 
105
 
 
106
/**
 
107
 * Generate a random GUID
 
108
 *
 
109
 * @v guid              GUID to fill in
 
110
 */
 
111
static void efi_snp_hii_random_guid ( EFI_GUID *guid ) {
 
112
        uint8_t *byte = ( ( uint8_t * ) guid );
 
113
        unsigned int i;
 
114
 
 
115
        for ( i = 0 ; i < sizeof ( *guid ) ; i++ )
 
116
                *(byte++) = random();
 
117
}
 
118
 
 
119
/**
 
120
 * Generate EFI SNP questions
 
121
 *
 
122
 * @v snpdev            SNP device
 
123
 * @v ifr               IFR builder
 
124
 * @v varstore_id       Variable store identifier
 
125
 */
 
126
static void efi_snp_hii_questions ( struct efi_snp_device *snpdev,
 
127
                                    struct efi_ifr_builder *ifr,
 
128
                                    unsigned int varstore_id ) {
 
129
        struct setting *setting;
 
130
        struct setting *previous = NULL;
 
131
        unsigned int name_id;
 
132
        unsigned int prompt_id;
 
133
        unsigned int help_id;
 
134
        unsigned int question_id;
 
135
 
 
136
        /* Add all applicable settings */
 
137
        for_each_table_entry ( setting, SETTINGS ) {
 
138
                if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
 
139
                        continue;
 
140
                if ( previous && ( setting_cmp ( setting, previous ) == 0 ) )
 
141
                        continue;
 
142
                previous = setting;
 
143
                name_id = efi_ifr_string ( ifr, "%s", setting->name );
 
144
                prompt_id = efi_ifr_string ( ifr, "%s", setting->description );
 
145
                help_id = efi_ifr_string ( ifr, PRODUCT_SETTING_URI,
 
146
                                           setting->name );
 
147
                question_id = setting->tag;
 
148
                efi_ifr_string_op ( ifr, prompt_id, help_id,
 
149
                                    question_id, varstore_id, name_id,
 
150
                                    0, 0x00, 0xff, 0 );
 
151
        }
 
152
}
 
153
 
 
154
/**
 
155
 * Build HII package list for SNP device
 
156
 *
 
157
 * @v snpdev            SNP device
 
158
 * @ret package         Package list, or NULL on error
 
159
 */
 
160
static EFI_HII_PACKAGE_LIST_HEADER *
 
161
efi_snp_hii_package_list ( struct efi_snp_device *snpdev ) {
 
162
        struct net_device *netdev = snpdev->netdev;
 
163
        struct device *dev = netdev->dev;
 
164
        struct efi_ifr_builder ifr;
 
165
        EFI_HII_PACKAGE_LIST_HEADER *package;
 
166
        const char *name;
 
167
        EFI_GUID package_guid;
 
168
        EFI_GUID formset_guid;
 
169
        EFI_GUID varstore_guid;
 
170
        unsigned int title_id;
 
171
        unsigned int varstore_id;
 
172
 
 
173
        /* Initialise IFR builder */
 
174
        efi_ifr_init ( &ifr );
 
175
 
 
176
        /* Determine product name */
 
177
        name = ( product_name[0] ? product_name : product_short_name );
 
178
 
 
179
        /* Generate GUIDs */
 
180
        efi_snp_hii_random_guid ( &package_guid );
 
181
        efi_snp_hii_random_guid ( &formset_guid );
 
182
        efi_snp_hii_random_guid ( &varstore_guid );
 
183
 
 
184
        /* Generate title string (used more than once) */
 
185
        title_id = efi_ifr_string ( &ifr, "%s (%s)", name,
 
186
                                    netdev_addr ( netdev ) );
 
187
 
 
188
        /* Generate opcodes */
 
189
        efi_ifr_form_set_op ( &ifr, &formset_guid, title_id,
 
190
                              efi_ifr_string ( &ifr, "Configure %s",
 
191
                                               product_short_name ),
 
192
                              &efi_hii_platform_setup_formset_guid,
 
193
                              &efi_hii_ibm_ucm_compliant_formset_guid, NULL );
 
194
        efi_ifr_guid_class_op ( &ifr, EFI_NETWORK_DEVICE_CLASS );
 
195
        efi_ifr_guid_subclass_op ( &ifr, 0x03 );
 
196
        varstore_id = efi_ifr_varstore_name_value_op ( &ifr, &varstore_guid );
 
197
        efi_ifr_form_op ( &ifr, title_id );
 
198
        efi_ifr_text_op ( &ifr,
 
199
                          efi_ifr_string ( &ifr, "Name" ),
 
200
                          efi_ifr_string ( &ifr, "Firmware product name" ),
 
201
                          efi_ifr_string ( &ifr, "%s", name ) );
 
202
        efi_ifr_text_op ( &ifr,
 
203
                          efi_ifr_string ( &ifr, "Version" ),
 
204
                          efi_ifr_string ( &ifr, "Firmware version" ),
 
205
                          efi_ifr_string ( &ifr, "%s", product_version ) );
 
206
        efi_ifr_text_op ( &ifr,
 
207
                          efi_ifr_string ( &ifr, "Driver" ),
 
208
                          efi_ifr_string ( &ifr, "Firmware driver" ),
 
209
                          efi_ifr_string ( &ifr, "%s", dev->driver_name ) );
 
210
        efi_ifr_text_op ( &ifr,
 
211
                          efi_ifr_string ( &ifr, "Device" ),
 
212
                          efi_ifr_string ( &ifr, "Hardware device" ),
 
213
                          efi_ifr_string ( &ifr, "%s", dev->name ) );
 
214
        efi_snp_hii_questions ( snpdev, &ifr, varstore_id );
 
215
        efi_ifr_end_op ( &ifr );
 
216
        efi_ifr_end_op ( &ifr );
 
217
 
 
218
        /* Build package */
 
219
        package = efi_ifr_package ( &ifr, &package_guid, "en-us",
 
220
                                    efi_ifr_string ( &ifr, "English" ) );
 
221
        if ( ! package ) {
 
222
                DBGC ( snpdev, "SNPDEV %p could not build IFR package\n",
 
223
                       snpdev );
 
224
                efi_ifr_free ( &ifr );
 
225
                return NULL;
 
226
        }
 
227
 
 
228
        /* Free temporary storage */
 
229
        efi_ifr_free ( &ifr );
 
230
        return package;
 
231
}
 
232
 
 
233
/**
 
234
 * Append response to result string
 
235
 *
 
236
 * @v snpdev            SNP device
 
237
 * @v key               Key
 
238
 * @v value             Value
 
239
 * @v results           Result string
 
240
 * @ret rc              Return status code
 
241
 *
 
242
 * The result string is allocated dynamically using
 
243
 * BootServices::AllocatePool(), and the caller is responsible for
 
244
 * eventually calling BootServices::FreePool().
 
245
 */
 
246
static int efi_snp_hii_append ( struct efi_snp_device *snpdev __unused,
 
247
                                const char *key, const char *value,
 
248
                                wchar_t **results ) {
 
249
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 
250
        size_t len;
 
251
        void *new;
 
252
 
 
253
        /* Allocate new string */
 
254
        len = ( ( *results ? ( wcslen ( *results ) + 1 /* "&" */ ) : 0 ) +
 
255
                strlen ( key ) + 1 /* "=" */ + strlen ( value ) + 1 /* NUL */ );
 
256
        bs->AllocatePool ( EfiBootServicesData, ( len * sizeof ( wchar_t ) ),
 
257
                           &new );
 
258
        if ( ! new )
 
259
                return -ENOMEM;
 
260
 
 
261
        /* Populate string */
 
262
        efi_snprintf ( new, len, "%ls%s%s=%s", ( *results ? *results : L"" ),
 
263
                       ( *results ? L"&" : L"" ), key, value );
 
264
        bs->FreePool ( *results );
 
265
        *results = new;
 
266
 
 
267
        return 0;
 
268
}
 
269
 
 
270
/**
 
271
 * Fetch HII setting
 
272
 *
 
273
 * @v snpdev            SNP device
 
274
 * @v key               Key
 
275
 * @v value             Value
 
276
 * @v results           Result string
 
277
 * @v have_setting      Flag indicating detection of a setting
 
278
 * @ret rc              Return status code
 
279
 */
 
280
static int efi_snp_hii_fetch ( struct efi_snp_device *snpdev,
 
281
                               const char *key, const char *value,
 
282
                               wchar_t **results, int *have_setting ) {
 
283
        struct settings *settings = efi_snp_hii_settings ( snpdev );
 
284
        struct settings *origin;
 
285
        struct setting *setting;
 
286
        struct setting fetched;
 
287
        int len;
 
288
        char *buf;
 
289
        char *encoded;
 
290
        int i;
 
291
        int rc;
 
292
 
 
293
        /* Handle ConfigHdr components */
 
294
        if ( ( strcasecmp ( key, "GUID" ) == 0 ) ||
 
295
             ( strcasecmp ( key, "NAME" ) == 0 ) ||
 
296
             ( strcasecmp ( key, "PATH" ) == 0 ) ) {
 
297
                return efi_snp_hii_append ( snpdev, key, value, results );
 
298
        }
 
299
        if ( have_setting )
 
300
                *have_setting = 1;
 
301
 
 
302
        /* Do nothing more unless we have a settings block */
 
303
        if ( ! settings ) {
 
304
                rc = -ENOTSUP;
 
305
                goto err_no_settings;
 
306
        }
 
307
 
 
308
        /* Identify setting */
 
309
        setting = find_setting ( key );
 
310
        if ( ! setting ) {
 
311
                DBGC ( snpdev, "SNPDEV %p no such setting \"%s\"\n",
 
312
                       snpdev, key );
 
313
                rc = -ENODEV;
 
314
                goto err_find_setting;
 
315
        }
 
316
 
 
317
        /* Encode value */
 
318
        if ( setting_exists ( settings, setting ) ) {
 
319
 
 
320
                /* Calculate formatted length */
 
321
                len = fetchf_setting ( settings, setting, &origin, &fetched,
 
322
                                       NULL, 0 );
 
323
                if ( len < 0 ) {
 
324
                        rc = len;
 
325
                        DBGC ( snpdev, "SNPDEV %p could not fetch %s: %s\n",
 
326
                               snpdev, setting->name, strerror ( rc ) );
 
327
                        goto err_fetchf_len;
 
328
                }
 
329
 
 
330
                /* Allocate buffer for formatted value and HII-encoded value */
 
331
                buf = zalloc ( len + 1 /* NUL */ + ( len * 4 ) + 1 /* NUL */ );
 
332
                if ( ! buf ) {
 
333
                        rc = -ENOMEM;
 
334
                        goto err_alloc;
 
335
                }
 
336
                encoded = ( buf + len + 1 /* NUL */ );
 
337
 
 
338
                /* Format value */
 
339
                fetchf_setting ( origin, &fetched, NULL, NULL, buf,
 
340
                                 ( len + 1 /* NUL */ ) );
 
341
                for ( i = 0 ; i < len ; i++ ) {
 
342
                        sprintf ( ( encoded + ( 4 * i ) ), "%04x",
 
343
                                  *( ( uint8_t * ) buf + i ) );
 
344
                }
 
345
 
 
346
        } else {
 
347
 
 
348
                /* Non-existent or inapplicable setting */
 
349
                buf = NULL;
 
350
                encoded = "";
 
351
        }
 
352
 
 
353
        /* Append results */
 
354
        if ( ( rc = efi_snp_hii_append ( snpdev, key, encoded,
 
355
                                         results ) ) != 0 ) {
 
356
                goto err_append;
 
357
        }
 
358
 
 
359
        /* Success */
 
360
        rc = 0;
 
361
 
 
362
 err_append:
 
363
        free ( buf );
 
364
 err_alloc:
 
365
 err_fetchf_len:
 
366
 err_find_setting:
 
367
 err_no_settings:
 
368
        return rc;
 
369
}
 
370
 
 
371
/**
 
372
 * Fetch HII setting
 
373
 *
 
374
 * @v snpdev            SNP device
 
375
 * @v key               Key
 
376
 * @v value             Value
 
377
 * @v results           Result string (unused)
 
378
 * @v have_setting      Flag indicating detection of a setting (unused)
 
379
 * @ret rc              Return status code
 
380
 */
 
381
static int efi_snp_hii_store ( struct efi_snp_device *snpdev,
 
382
                               const char *key, const char *value,
 
383
                               wchar_t **results __unused,
 
384
                               int *have_setting __unused ) {
 
385
        struct settings *settings = efi_snp_hii_settings ( snpdev );
 
386
        struct setting *setting;
 
387
        char *buf;
 
388
        char tmp[5];
 
389
        char *endp;
 
390
        int len;
 
391
        int i;
 
392
        int rc;
 
393
 
 
394
        /* Handle ConfigHdr components */
 
395
        if ( ( strcasecmp ( key, "GUID" ) == 0 ) ||
 
396
             ( strcasecmp ( key, "NAME" ) == 0 ) ||
 
397
             ( strcasecmp ( key, "PATH" ) == 0 ) ) {
 
398
                /* Nothing to do */
 
399
                return 0;
 
400
        }
 
401
 
 
402
        /* Do nothing more unless we have a settings block */
 
403
        if ( ! settings ) {
 
404
                rc = -ENOTSUP;
 
405
                goto err_no_settings;
 
406
        }
 
407
 
 
408
        /* Identify setting */
 
409
        setting = find_setting ( key );
 
410
        if ( ! setting ) {
 
411
                DBGC ( snpdev, "SNPDEV %p no such setting \"%s\"\n",
 
412
                       snpdev, key );
 
413
                rc = -ENODEV;
 
414
                goto err_find_setting;
 
415
        }
 
416
 
 
417
        /* Allocate buffer */
 
418
        len = ( strlen ( value ) / 4 );
 
419
        buf = zalloc ( len + 1 /* NUL */ );
 
420
        if ( ! buf ) {
 
421
                rc = -ENOMEM;
 
422
                goto err_alloc;
 
423
        }
 
424
 
 
425
        /* Decode value */
 
426
        tmp[4] = '\0';
 
427
        for ( i = 0 ; i < len ; i++ ) {
 
428
                memcpy ( tmp, ( value + ( i * 4 ) ), 4 );
 
429
                buf[i] = strtoul ( tmp, &endp, 16 );
 
430
                if ( endp != &tmp[4] ) {
 
431
                        DBGC ( snpdev, "SNPDEV %p invalid character %s\n",
 
432
                               snpdev, tmp );
 
433
                        rc = -EINVAL;
 
434
                        goto err_inval;
 
435
                }
 
436
        }
 
437
 
 
438
        /* Store value */
 
439
        if ( ( rc = storef_setting ( settings, setting, buf ) ) != 0 ) {
 
440
                DBGC ( snpdev, "SNPDEV %p could not store \"%s\" into %s: %s\n",
 
441
                       snpdev, buf, setting->name, strerror ( rc ) );
 
442
                goto err_storef;
 
443
        }
 
444
 
 
445
        /* Success */
 
446
        rc = 0;
 
447
 
 
448
 err_storef:
 
449
 err_inval:
 
450
        free ( buf );
 
451
 err_alloc:
 
452
 err_find_setting:
 
453
 err_no_settings:
 
454
        return rc;
 
455
}
 
456
 
 
457
/**
 
458
 * Process portion of HII configuration string
 
459
 *
 
460
 * @v snpdev            SNP device
 
461
 * @v string            HII configuration string
 
462
 * @v progress          Progress through HII configuration string
 
463
 * @v results           Results string
 
464
 * @v have_setting      Flag indicating detection of a setting (unused)
 
465
 * @v process           Function used to process key=value pairs
 
466
 * @ret rc              Return status code
 
467
 */
 
468
static int efi_snp_hii_process ( struct efi_snp_device *snpdev,
 
469
                                 wchar_t *string, wchar_t **progress,
 
470
                                 wchar_t **results, int *have_setting,
 
471
                                 int ( * process ) ( struct efi_snp_device *,
 
472
                                                     const char *key,
 
473
                                                     const char *value,
 
474
                                                     wchar_t **results,
 
475
                                                     int *have_setting ) ) {
 
476
        wchar_t *wkey = string;
 
477
        wchar_t *wend = string;
 
478
        wchar_t *wvalue = NULL;
 
479
        size_t key_len;
 
480
        size_t value_len;
 
481
        void *temp;
 
482
        char *key;
 
483
        char *value;
 
484
        int rc;
 
485
 
 
486
        /* Locate key, value (if any), and end */
 
487
        while ( *wend ) {
 
488
                if ( *wend == L'&' )
 
489
                        break;
 
490
                if ( *(wend++) == L'=' )
 
491
                        wvalue = wend;
 
492
        }
 
493
 
 
494
        /* Allocate memory for key and value */
 
495
        key_len = ( ( wvalue ? ( wvalue - 1 ) : wend ) - wkey );
 
496
        value_len = ( wvalue ? ( wend - wvalue ) : 0 );
 
497
        temp = zalloc ( key_len + 1 /* NUL */ + value_len + 1 /* NUL */ );
 
498
        if ( ! temp )
 
499
                return -ENOMEM;
 
500
        key = temp;
 
501
        value = ( temp + key_len + 1 /* NUL */ );
 
502
 
 
503
        /* Copy key and value */
 
504
        while ( key_len-- )
 
505
                key[key_len] = wkey[key_len];
 
506
        while ( value_len-- )
 
507
                value[value_len] = wvalue[value_len];
 
508
 
 
509
        /* Process key and value */
 
510
        if ( ( rc = process ( snpdev, key, value, results,
 
511
                              have_setting ) ) != 0 ) {
 
512
                goto err;
 
513
        }
 
514
 
 
515
        /* Update progress marker */
 
516
        *progress = wend;
 
517
 
 
518
 err:
 
519
        /* Free temporary storage */
 
520
        free ( temp );
 
521
 
 
522
        return rc;
 
523
}
 
524
 
 
525
/**
 
526
 * Fetch configuration
 
527
 *
 
528
 * @v hii               HII configuration access protocol
 
529
 * @v request           Configuration to fetch
 
530
 * @ret progress        Progress made through configuration to fetch
 
531
 * @ret results         Query results
 
532
 * @ret efirc           EFI status code
 
533
 */
 
534
static EFI_STATUS EFIAPI
 
535
efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
 
536
                             EFI_STRING request, EFI_STRING *progress,
 
537
                             EFI_STRING *results ) {
 
538
        struct efi_snp_device *snpdev =
 
539
                container_of ( hii, struct efi_snp_device, hii );
 
540
        int have_setting = 0;
 
541
        wchar_t *pos;
 
542
        int rc;
 
543
 
 
544
        DBGC ( snpdev, "SNPDEV %p ExtractConfig request \"%ls\"\n",
 
545
               snpdev, request );
 
546
 
 
547
        /* Initialise results */
 
548
        *results = NULL;
 
549
 
 
550
        /* Work around apparently broken UEFI specification */
 
551
        if ( ! ( request && request[0] ) ) {
 
552
                DBGC ( snpdev, "SNPDEV %p ExtractConfig ignoring malformed "
 
553
                       "request\n", snpdev );
 
554
                return EFI_INVALID_PARAMETER;
 
555
        }
 
556
 
 
557
        /* Process all request fragments */
 
558
        for ( pos = *progress = request ; *progress && **progress ;
 
559
              pos = *progress + 1 ) {
 
560
                if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
 
561
                                                  results, &have_setting,
 
562
                                                  efi_snp_hii_fetch ) ) != 0 ) {
 
563
                        return EFIRC ( rc );
 
564
                }
 
565
        }
 
566
 
 
567
        /* If we have no explicit request, return all settings */
 
568
        if ( ! have_setting ) {
 
569
                struct setting *setting;
 
570
 
 
571
                for_each_table_entry ( setting, SETTINGS ) {
 
572
                        if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
 
573
                                continue;
 
574
                        if ( ( rc = efi_snp_hii_fetch ( snpdev, setting->name,
 
575
                                                        NULL, results,
 
576
                                                        NULL ) ) != 0 ) {
 
577
                                return EFIRC ( rc );
 
578
                        }
 
579
                }
 
580
        }
 
581
 
 
582
        DBGC ( snpdev, "SNPDEV %p ExtractConfig results \"%ls\"\n",
 
583
               snpdev, *results );
 
584
        return 0;
 
585
}
 
586
 
 
587
/**
 
588
 * Store configuration
 
589
 *
 
590
 * @v hii               HII configuration access protocol
 
591
 * @v config            Configuration to store
 
592
 * @ret progress        Progress made through configuration to store
 
593
 * @ret efirc           EFI status code
 
594
 */
 
595
static EFI_STATUS EFIAPI
 
596
efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
 
597
                           EFI_STRING config, EFI_STRING *progress ) {
 
598
        struct efi_snp_device *snpdev =
 
599
                container_of ( hii, struct efi_snp_device, hii );
 
600
        wchar_t *pos;
 
601
        int rc;
 
602
 
 
603
        DBGC ( snpdev, "SNPDEV %p RouteConfig \"%ls\"\n", snpdev, config );
 
604
 
 
605
        /* Process all request fragments */
 
606
        for ( pos = *progress = config ; *progress && **progress ;
 
607
              pos = *progress + 1 ) {
 
608
                if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
 
609
                                                  NULL, NULL,
 
610
                                                  efi_snp_hii_store ) ) != 0 ) {
 
611
                        return EFIRC ( rc );
 
612
                }
 
613
        }
 
614
 
 
615
        return 0;
 
616
}
 
617
 
 
618
/**
 
619
 * Handle form actions
 
620
 *
 
621
 * @v hii               HII configuration access protocol
 
622
 * @v action            Form browser action
 
623
 * @v question_id       Question ID
 
624
 * @v type              Type of value
 
625
 * @v value             Value
 
626
 * @ret action_request  Action requested by driver
 
627
 * @ret efirc           EFI status code
 
628
 */
 
629
static EFI_STATUS EFIAPI
 
630
efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
 
631
                       EFI_BROWSER_ACTION action __unused,
 
632
                       EFI_QUESTION_ID question_id __unused,
 
633
                       UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused,
 
634
                       EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
 
635
        struct efi_snp_device *snpdev =
 
636
                container_of ( hii, struct efi_snp_device, hii );
 
637
 
 
638
        DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
 
639
        return EFI_UNSUPPORTED;
 
640
}
 
641
 
 
642
/** HII configuration access protocol */
 
643
static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = {
 
644
        .ExtractConfig  = efi_snp_hii_extract_config,
 
645
        .RouteConfig    = efi_snp_hii_route_config,
 
646
        .Callback       = efi_snp_hii_callback,
 
647
};
 
648
 
 
649
/**
 
650
 * Install HII protocol and packages for SNP device
 
651
 *
 
652
 * @v snpdev            SNP device
 
653
 * @ret rc              Return status code
 
654
 */
 
655
int efi_snp_hii_install ( struct efi_snp_device *snpdev ) {
 
656
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 
657
        VENDOR_DEVICE_PATH *vendor_path;
 
658
        EFI_DEVICE_PATH_PROTOCOL *path_end;
 
659
        size_t path_prefix_len;
 
660
        int efirc;
 
661
        int rc;
 
662
 
 
663
        /* Do nothing if HII database protocol is not supported */
 
664
        if ( ! efihii ) {
 
665
                rc = -ENOTSUP;
 
666
                goto err_no_hii;
 
667
        }
 
668
 
 
669
        /* Initialise HII protocol */
 
670
        memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
 
671
 
 
672
        /* Create HII package list */
 
673
        snpdev->package_list = efi_snp_hii_package_list ( snpdev );
 
674
        if ( ! snpdev->package_list ) {
 
675
                DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
 
676
                       snpdev );
 
677
                rc = -ENOMEM;
 
678
                goto err_build_package_list;
 
679
        }
 
680
 
 
681
        /* Allocate the new device path */
 
682
        path_prefix_len = efi_devpath_len ( snpdev->path );
 
683
        snpdev->hii_child_path = zalloc ( path_prefix_len +
 
684
                                          sizeof ( *vendor_path ) +
 
685
                                          sizeof ( *path_end ) );
 
686
        if ( ! snpdev->hii_child_path ) {
 
687
                DBGC ( snpdev,
 
688
                       "SNPDEV %p could not allocate HII child device path\n",
 
689
                       snpdev );
 
690
                rc = -ENOMEM;
 
691
                goto err_alloc_child_path;
 
692
        }
 
693
 
 
694
        /* Populate the device path */
 
695
        memcpy ( snpdev->hii_child_path, snpdev->path, path_prefix_len );
 
696
        vendor_path = ( ( ( void * ) snpdev->hii_child_path ) +
 
697
                        path_prefix_len );
 
698
        vendor_path->Header.Type = HARDWARE_DEVICE_PATH;
 
699
        vendor_path->Header.SubType = HW_VENDOR_DP;
 
700
        vendor_path->Header.Length[0] = sizeof ( *vendor_path );
 
701
        efi_snp_hii_random_guid ( &vendor_path->Guid );
 
702
        path_end = ( ( void * ) ( vendor_path + 1 ) );
 
703
        path_end->Type = END_DEVICE_PATH_TYPE;
 
704
        path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
 
705
        path_end->Length[0] = sizeof ( *path_end );
 
706
 
 
707
        /* Create device path and child handle for HII association */
 
708
        if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
 
709
                        &snpdev->hii_child_handle,
 
710
                        &efi_device_path_protocol_guid, snpdev->hii_child_path,
 
711
                        NULL ) ) != 0 ) {
 
712
                rc = -EEFI ( efirc );
 
713
                DBGC ( snpdev, "SNPDEV %p could not create HII child handle: "
 
714
                       "%s\n", snpdev, strerror ( rc ) );
 
715
                goto err_hii_child_handle;
 
716
        }
 
717
 
 
718
        /* Add HII packages */
 
719
        if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
 
720
                                                snpdev->hii_child_handle,
 
721
                                                &snpdev->hii_handle ) ) != 0 ) {
 
722
                rc = -EEFI ( efirc );
 
723
                DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
 
724
                       snpdev, strerror ( rc ) );
 
725
                goto err_new_package_list;
 
726
        }
 
727
 
 
728
        /* Install HII protocol */
 
729
        if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
 
730
                         &snpdev->hii_child_handle,
 
731
                         &efi_hii_config_access_protocol_guid, &snpdev->hii,
 
732
                         NULL ) ) != 0 ) {
 
733
                rc = -EEFI ( efirc );
 
734
                DBGC ( snpdev, "SNPDEV %p could not install HII protocol: %s\n",
 
735
                       snpdev, strerror ( rc ) );
 
736
                goto err_install_protocol;
 
737
        }
 
738
 
 
739
        /* Add as child of handle with SNP instance */
 
740
        if ( ( rc = efi_child_add ( snpdev->handle,
 
741
                                    snpdev->hii_child_handle ) ) != 0 ) {
 
742
                DBGC ( snpdev,
 
743
                       "SNPDEV %p could not adopt HII child handle: %s\n",
 
744
                       snpdev, strerror ( rc ) );
 
745
                goto err_efi_child_add;
 
746
        }
 
747
 
 
748
        return 0;
 
749
 
 
750
        efi_child_del ( snpdev->handle, snpdev->hii_child_handle );
 
751
 err_efi_child_add:
 
752
        bs->UninstallMultipleProtocolInterfaces (
 
753
                        snpdev->hii_child_handle,
 
754
                        &efi_hii_config_access_protocol_guid, &snpdev->hii,
 
755
                        NULL );
 
756
 err_install_protocol:
 
757
        efihii->RemovePackageList ( efihii, snpdev->hii_handle );
 
758
 err_new_package_list:
 
759
        bs->UninstallMultipleProtocolInterfaces (
 
760
                        snpdev->hii_child_handle,
 
761
                        &efi_device_path_protocol_guid, snpdev->hii_child_path,
 
762
                        NULL );
 
763
 err_hii_child_handle:
 
764
        free ( snpdev->hii_child_path );
 
765
        snpdev->hii_child_path = NULL;
 
766
 err_alloc_child_path:
 
767
        free ( snpdev->package_list );
 
768
        snpdev->package_list = NULL;
 
769
 err_build_package_list:
 
770
 err_no_hii:
 
771
        return rc;
 
772
}
 
773
 
 
774
/**
 
775
 * Uninstall HII protocol and package for SNP device
 
776
 *
 
777
 * @v snpdev            SNP device
 
778
 */
 
779
void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) {
 
780
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 
781
 
 
782
        /* Do nothing if HII database protocol is not supported */
 
783
        if ( ! efihii )
 
784
                return;
 
785
 
 
786
        /* Uninstall protocols and remove package list */
 
787
        efi_child_del ( snpdev->handle, snpdev->hii_child_handle );
 
788
        bs->UninstallMultipleProtocolInterfaces (
 
789
                        snpdev->hii_child_handle,
 
790
                        &efi_hii_config_access_protocol_guid, &snpdev->hii,
 
791
                        NULL );
 
792
        efihii->RemovePackageList ( efihii, snpdev->hii_handle );
 
793
        bs->UninstallMultipleProtocolInterfaces (
 
794
                        snpdev->hii_child_handle,
 
795
                        &efi_device_path_protocol_guid, snpdev->hii_child_path,
 
796
                        NULL );
 
797
        free ( snpdev->hii_child_path );
 
798
        snpdev->hii_child_path = NULL;
 
799
        free ( snpdev->package_list );
 
800
        snpdev->package_list = NULL;
 
801
}