You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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