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.

efi_hii.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  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. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdlib.h>
  25. #include <stddef.h>
  26. #include <stdarg.h>
  27. #include <string.h>
  28. #include <ipxe/efi/efi.h>
  29. #include <ipxe/efi/efi_strings.h>
  30. #include <ipxe/efi/efi_hii.h>
  31. /** Tiano GUID */
  32. static const EFI_GUID tiano_guid = EFI_IFR_TIANO_GUID;
  33. /**
  34. * Add string to IFR builder
  35. *
  36. * @v ifr IFR builder
  37. * @v fmt Format string
  38. * @v ... Arguments
  39. * @ret string_id String identifier, or zero on failure
  40. */
  41. unsigned int efi_ifr_string ( struct efi_ifr_builder *ifr, const char *fmt,
  42. ... ) {
  43. EFI_HII_STRING_BLOCK *new_strings;
  44. EFI_HII_SIBT_STRING_UCS2_BLOCK *ucs2;
  45. size_t new_strings_len;
  46. va_list args;
  47. size_t len;
  48. unsigned int string_id;
  49. /* Do nothing if a previous allocation has failed */
  50. if ( ifr->failed )
  51. return 0;
  52. /* Calculate string length */
  53. va_start ( args, fmt );
  54. len = ( efi_vsnprintf ( NULL, 0, fmt, args ) + 1 /* wNUL */ );
  55. va_end ( args );
  56. /* Reallocate strings */
  57. new_strings_len = ( ifr->strings_len +
  58. offsetof ( typeof ( *ucs2 ), StringText ) +
  59. ( len * sizeof ( ucs2->StringText[0] ) ) );
  60. new_strings = realloc ( ifr->strings, new_strings_len );
  61. if ( ! new_strings ) {
  62. ifr->failed = 1;
  63. return 0;
  64. }
  65. ucs2 = ( ( ( void * ) new_strings ) + ifr->strings_len );
  66. ifr->strings = new_strings;
  67. ifr->strings_len = new_strings_len;
  68. /* Fill in string */
  69. ucs2->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
  70. va_start ( args, fmt );
  71. efi_vsnprintf ( ucs2->StringText, len, fmt, args );
  72. va_end ( args );
  73. /* Allocate string ID */
  74. string_id = ++(ifr->string_id);
  75. DBGC ( ifr, "IFR %p string %#04x is \"%ls\"\n",
  76. ifr, string_id, ucs2->StringText );
  77. return string_id;
  78. }
  79. /**
  80. * Add IFR opcode to IFR builder
  81. *
  82. * @v ifr IFR builder
  83. * @v opcode Opcode
  84. * @v len Opcode length
  85. * @ret op Opcode, or NULL
  86. */
  87. static void * efi_ifr_op ( struct efi_ifr_builder *ifr, unsigned int opcode,
  88. size_t len ) {
  89. EFI_IFR_OP_HEADER *new_ops;
  90. EFI_IFR_OP_HEADER *op;
  91. size_t new_ops_len;
  92. /* Do nothing if a previous allocation has failed */
  93. if ( ifr->failed )
  94. return NULL;
  95. /* Reallocate opcodes */
  96. new_ops_len = ( ifr->ops_len + len );
  97. new_ops = realloc ( ifr->ops, new_ops_len );
  98. if ( ! new_ops ) {
  99. ifr->failed = 1;
  100. return NULL;
  101. }
  102. op = ( ( ( void * ) new_ops ) + ifr->ops_len );
  103. ifr->ops = new_ops;
  104. ifr->ops_len = new_ops_len;
  105. /* Fill in opcode header */
  106. memset ( op, 0, len );
  107. op->OpCode = opcode;
  108. op->Length = len;
  109. return op;
  110. }
  111. /**
  112. * Add end opcode to IFR builder
  113. *
  114. * @v ifr IFR builder
  115. */
  116. void efi_ifr_end_op ( struct efi_ifr_builder *ifr ) {
  117. size_t dispaddr = ifr->ops_len;
  118. EFI_IFR_END *end;
  119. /* Add opcode */
  120. end = efi_ifr_op ( ifr, EFI_IFR_END_OP, sizeof ( *end ) );
  121. DBGC ( ifr, "IFR %p end\n", ifr );
  122. DBGC2_HDA ( ifr, dispaddr, end, sizeof ( *end ) );
  123. }
  124. /**
  125. * Add false opcode to IFR builder
  126. *
  127. * @v ifr IFR builder
  128. */
  129. void efi_ifr_false_op ( struct efi_ifr_builder *ifr ) {
  130. size_t dispaddr = ifr->ops_len;
  131. EFI_IFR_FALSE *false;
  132. /* Add opcode */
  133. false = efi_ifr_op ( ifr, EFI_IFR_FALSE_OP, sizeof ( *false ) );
  134. DBGC ( ifr, "IFR %p false\n", ifr );
  135. DBGC2_HDA ( ifr, dispaddr, false, sizeof ( *false ) );
  136. }
  137. /**
  138. * Add form opcode to IFR builder
  139. *
  140. * @v ifr IFR builder
  141. * @v title_id Title string identifier
  142. * @ret form_id Form identifier
  143. */
  144. unsigned int efi_ifr_form_op ( struct efi_ifr_builder *ifr,
  145. unsigned int title_id ) {
  146. size_t dispaddr = ifr->ops_len;
  147. EFI_IFR_FORM *form;
  148. /* Add opcode */
  149. form = efi_ifr_op ( ifr, EFI_IFR_FORM_OP, sizeof ( *form ) );
  150. if ( ! form )
  151. return 0;
  152. form->Header.Scope = 1;
  153. form->FormId = ++(ifr->form_id);
  154. form->FormTitle = title_id;
  155. DBGC ( ifr, "IFR %p name/value store %#04x title %#04x\n",
  156. ifr, form->FormId, title_id );
  157. DBGC2_HDA ( ifr, dispaddr, form, sizeof ( *form ) );
  158. return form->FormId;
  159. }
  160. /**
  161. * Add formset opcode to IFR builder
  162. *
  163. * @v ifr IFR builder
  164. * @v guid GUID
  165. * @v title_id Title string identifier
  166. * @v help_id Help string identifier
  167. * @v ... Class GUIDs (terminated by NULL)
  168. */
  169. void efi_ifr_form_set_op ( struct efi_ifr_builder *ifr, const EFI_GUID *guid,
  170. unsigned int title_id, unsigned int help_id, ... ) {
  171. size_t dispaddr = ifr->ops_len;
  172. EFI_IFR_FORM_SET *formset;
  173. EFI_GUID *class_guid;
  174. unsigned int num_class_guids = 0;
  175. size_t len;
  176. va_list args;
  177. /* Count number of class GUIDs */
  178. va_start ( args, help_id );
  179. while ( va_arg ( args, const EFI_GUID * ) != NULL )
  180. num_class_guids++;
  181. va_end ( args );
  182. /* Add opcode */
  183. len = ( sizeof ( *formset ) +
  184. ( num_class_guids * sizeof ( *class_guid ) ) );
  185. formset = efi_ifr_op ( ifr, EFI_IFR_FORM_SET_OP, len );
  186. if ( ! formset )
  187. return;
  188. formset->Header.Scope = 1;
  189. memcpy ( &formset->Guid, guid, sizeof ( formset->Guid ) );
  190. formset->FormSetTitle = title_id;
  191. formset->Help = help_id;
  192. formset->Flags = num_class_guids;
  193. /* Add class GUIDs */
  194. class_guid = ( ( ( void * ) formset ) + sizeof ( *formset ) );
  195. va_start ( args, help_id );
  196. while ( num_class_guids-- ) {
  197. memcpy ( class_guid++, va_arg ( args, const EFI_GUID * ),
  198. sizeof ( *class_guid ) );
  199. }
  200. va_end ( args );
  201. DBGC ( ifr, "IFR %p formset title %#04x help %#04x\n",
  202. ifr, title_id, help_id );
  203. DBGC2_HDA ( ifr, dispaddr, formset, len );
  204. }
  205. /**
  206. * Add get opcode to IFR builder
  207. *
  208. * @v ifr IFR builder
  209. * @v varstore_id Variable store identifier
  210. * @v varstore_info Variable string identifier or offset
  211. * @v varstore_type Variable type
  212. */
  213. void efi_ifr_get_op ( struct efi_ifr_builder *ifr, unsigned int varstore_id,
  214. unsigned int varstore_info, unsigned int varstore_type ) {
  215. size_t dispaddr = ifr->ops_len;
  216. EFI_IFR_GET *get;
  217. /* Add opcode */
  218. get = efi_ifr_op ( ifr, EFI_IFR_GET_OP, sizeof ( *get ) );
  219. get->VarStoreId = varstore_id;
  220. get->VarStoreInfo.VarName = varstore_info;
  221. get->VarStoreType = varstore_type;
  222. DBGC ( ifr, "IFR %p get varstore %#04x:%#04x type %#02x\n",
  223. ifr, varstore_id, varstore_info, varstore_type );
  224. DBGC2_HDA ( ifr, dispaddr, get, sizeof ( *get ) );
  225. }
  226. /**
  227. * Add GUID class opcode to IFR builder
  228. *
  229. * @v ifr IFR builder
  230. * @v class Class
  231. */
  232. void efi_ifr_guid_class_op ( struct efi_ifr_builder *ifr, unsigned int class ) {
  233. size_t dispaddr = ifr->ops_len;
  234. EFI_IFR_GUID_CLASS *guid_class;
  235. /* Add opcode */
  236. guid_class = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
  237. sizeof ( *guid_class ) );
  238. if ( ! guid_class )
  239. return;
  240. memcpy ( &guid_class->Guid, &tiano_guid, sizeof ( guid_class->Guid ) );
  241. guid_class->ExtendOpCode = EFI_IFR_EXTEND_OP_CLASS;
  242. guid_class->Class = class;
  243. DBGC ( ifr, "IFR %p GUID class %#02x\n", ifr, class );
  244. DBGC2_HDA ( ifr, dispaddr, guid_class, sizeof ( *guid_class ) );
  245. }
  246. /**
  247. * Add GUID subclass opcode to IFR builder
  248. *
  249. * @v ifr IFR builder
  250. * @v subclass Subclass
  251. */
  252. void efi_ifr_guid_subclass_op ( struct efi_ifr_builder *ifr,
  253. unsigned int subclass ) {
  254. size_t dispaddr = ifr->ops_len;
  255. EFI_IFR_GUID_SUBCLASS *guid_subclass;
  256. /* Add opcode */
  257. guid_subclass = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
  258. sizeof ( *guid_subclass ) );
  259. if ( ! guid_subclass )
  260. return;
  261. memcpy ( &guid_subclass->Guid, &tiano_guid,
  262. sizeof ( guid_subclass->Guid ) );
  263. guid_subclass->ExtendOpCode = EFI_IFR_EXTEND_OP_SUBCLASS;
  264. guid_subclass->SubClass = subclass;
  265. DBGC ( ifr, "IFR %p GUID subclass %#02x\n", ifr, subclass );
  266. DBGC2_HDA ( ifr, dispaddr, guid_subclass, sizeof ( *guid_subclass ) );
  267. }
  268. /**
  269. * Add numeric opcode to IFR builder
  270. *
  271. * @v ifr IFR builder
  272. * @v prompt_id Prompt string identifier
  273. * @v help_id Help string identifier
  274. * @v question_id Question identifier
  275. * @v varstore_id Variable store identifier
  276. * @v varstore_info Variable string identifier or offset
  277. * @v vflags Variable flags
  278. * @v min_value Minimum value
  279. * @v max_value Maximum value
  280. * @v step Step
  281. * @v flags Flags
  282. */
  283. void efi_ifr_numeric_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
  284. unsigned int help_id, unsigned int question_id,
  285. unsigned int varstore_id, unsigned int varstore_info,
  286. unsigned int vflags, unsigned long min_value,
  287. unsigned long max_value, unsigned int step,
  288. unsigned int flags ) {
  289. size_t dispaddr = ifr->ops_len;
  290. EFI_IFR_NUMERIC *numeric;
  291. unsigned int size;
  292. /* Add opcode */
  293. numeric = efi_ifr_op ( ifr, EFI_IFR_NUMERIC_OP, sizeof ( *numeric ) );
  294. if ( ! numeric )
  295. return;
  296. numeric->Question.Header.Prompt = prompt_id;
  297. numeric->Question.Header.Help = help_id;
  298. numeric->Question.QuestionId = question_id;
  299. numeric->Question.VarStoreId = varstore_id;
  300. numeric->Question.VarStoreInfo.VarName = varstore_info;
  301. numeric->Question.Flags = vflags;
  302. size = ( flags & EFI_IFR_NUMERIC_SIZE );
  303. switch ( size ) {
  304. case EFI_IFR_NUMERIC_SIZE_1 :
  305. numeric->data.u8.MinValue = min_value;
  306. numeric->data.u8.MaxValue = max_value;
  307. numeric->data.u8.Step = step;
  308. break;
  309. case EFI_IFR_NUMERIC_SIZE_2 :
  310. numeric->data.u16.MinValue = min_value;
  311. numeric->data.u16.MaxValue = max_value;
  312. numeric->data.u16.Step = step;
  313. break;
  314. case EFI_IFR_NUMERIC_SIZE_4 :
  315. numeric->data.u32.MinValue = min_value;
  316. numeric->data.u32.MaxValue = max_value;
  317. numeric->data.u32.Step = step;
  318. break;
  319. case EFI_IFR_NUMERIC_SIZE_8 :
  320. numeric->data.u64.MinValue = min_value;
  321. numeric->data.u64.MaxValue = max_value;
  322. numeric->data.u64.Step = step;
  323. break;
  324. }
  325. DBGC ( ifr, "IFR %p numeric prompt %#04x help %#04x question %#04x "
  326. "varstore %#04x:%#04x\n", ifr, prompt_id, help_id, question_id,
  327. varstore_id, varstore_info );
  328. DBGC2_HDA ( ifr, dispaddr, numeric, sizeof ( *numeric ) );
  329. }
  330. /**
  331. * Add string opcode to IFR builder
  332. *
  333. * @v ifr IFR builder
  334. * @v prompt_id Prompt string identifier
  335. * @v help_id Help string identifier
  336. * @v question_id Question identifier
  337. * @v varstore_id Variable store identifier
  338. * @v varstore_info Variable string identifier or offset
  339. * @v vflags Variable flags
  340. * @v min_size Minimum size
  341. * @v max_size Maximum size
  342. * @v flags Flags
  343. */
  344. void efi_ifr_string_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
  345. unsigned int help_id, unsigned int question_id,
  346. unsigned int varstore_id, unsigned int varstore_info,
  347. unsigned int vflags, unsigned int min_size,
  348. unsigned int max_size, unsigned int flags ) {
  349. size_t dispaddr = ifr->ops_len;
  350. EFI_IFR_STRING *string;
  351. /* Add opcode */
  352. string = efi_ifr_op ( ifr, EFI_IFR_STRING_OP, sizeof ( *string ) );
  353. if ( ! string )
  354. return;
  355. string->Question.Header.Prompt = prompt_id;
  356. string->Question.Header.Help = help_id;
  357. string->Question.QuestionId = question_id;
  358. string->Question.VarStoreId = varstore_id;
  359. string->Question.VarStoreInfo.VarName = varstore_info;
  360. string->Question.Flags = vflags;
  361. string->MinSize = min_size;
  362. string->MaxSize = max_size;
  363. string->Flags = flags;
  364. DBGC ( ifr, "IFR %p string prompt %#04x help %#04x question %#04x "
  365. "varstore %#04x:%#04x\n", ifr, prompt_id, help_id, question_id,
  366. varstore_id, varstore_info );
  367. DBGC2_HDA ( ifr, dispaddr, string, sizeof ( *string ) );
  368. }
  369. /**
  370. * Add suppress-if opcode to IFR builder
  371. *
  372. * @v ifr IFR builder
  373. */
  374. void efi_ifr_suppress_if_op ( struct efi_ifr_builder *ifr ) {
  375. size_t dispaddr = ifr->ops_len;
  376. EFI_IFR_SUPPRESS_IF *suppress_if;
  377. /* Add opcode */
  378. suppress_if = efi_ifr_op ( ifr, EFI_IFR_SUPPRESS_IF_OP,
  379. sizeof ( *suppress_if ) );
  380. suppress_if->Header.Scope = 1;
  381. DBGC ( ifr, "IFR %p suppress-if\n", ifr );
  382. DBGC2_HDA ( ifr, dispaddr, suppress_if, sizeof ( *suppress_if ) );
  383. }
  384. /**
  385. * Add text opcode to IFR builder
  386. *
  387. * @v ifr IFR builder
  388. * @v prompt_id Prompt string identifier
  389. * @v help_id Help string identifier
  390. * @v text_id Text string identifier
  391. */
  392. void efi_ifr_text_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
  393. unsigned int help_id, unsigned int text_id ) {
  394. size_t dispaddr = ifr->ops_len;
  395. EFI_IFR_TEXT *text;
  396. /* Add opcode */
  397. text = efi_ifr_op ( ifr, EFI_IFR_TEXT_OP, sizeof ( *text ) );
  398. if ( ! text )
  399. return;
  400. text->Statement.Prompt = prompt_id;
  401. text->Statement.Help = help_id;
  402. text->TextTwo = text_id;
  403. DBGC ( ifr, "IFR %p text prompt %#04x help %#04x text %#04x\n",
  404. ifr, prompt_id, help_id, text_id );
  405. DBGC2_HDA ( ifr, dispaddr, text, sizeof ( *text ) );
  406. }
  407. /**
  408. * Add true opcode to IFR builder
  409. *
  410. * @v ifr IFR builder
  411. */
  412. void efi_ifr_true_op ( struct efi_ifr_builder *ifr ) {
  413. size_t dispaddr = ifr->ops_len;
  414. EFI_IFR_TRUE *true;
  415. /* Add opcode */
  416. true = efi_ifr_op ( ifr, EFI_IFR_TRUE_OP, sizeof ( *true ) );
  417. DBGC ( ifr, "IFR %p true\n", ifr );
  418. DBGC2_HDA ( ifr, dispaddr, true, sizeof ( *true ) );
  419. }
  420. /**
  421. * Add name/value store opcode to IFR builder
  422. *
  423. * @v ifr IFR builder
  424. * @v guid GUID
  425. * @ret varstore_id Variable store identifier, or 0 on failure
  426. */
  427. unsigned int efi_ifr_varstore_name_value_op ( struct efi_ifr_builder *ifr,
  428. const EFI_GUID *guid ) {
  429. size_t dispaddr = ifr->ops_len;
  430. EFI_IFR_VARSTORE_NAME_VALUE *varstore;
  431. /* Add opcode */
  432. varstore = efi_ifr_op ( ifr, EFI_IFR_VARSTORE_NAME_VALUE_OP,
  433. sizeof ( *varstore ) );
  434. if ( ! varstore )
  435. return 0;
  436. varstore->VarStoreId = ++(ifr->varstore_id);
  437. memcpy ( &varstore->Guid, guid, sizeof ( varstore->Guid ) );
  438. DBGC ( ifr, "IFR %p name/value store %#04x\n",
  439. ifr, varstore->VarStoreId );
  440. DBGC2_HDA ( ifr, dispaddr, varstore, sizeof ( *varstore ) );
  441. return varstore->VarStoreId;
  442. }
  443. /**
  444. * Free memory used by IFR builder
  445. *
  446. * @v ifr IFR builder
  447. */
  448. void efi_ifr_free ( struct efi_ifr_builder *ifr ) {
  449. free ( ifr->ops );
  450. free ( ifr->strings );
  451. memset ( ifr, 0, sizeof ( *ifr ) );
  452. }
  453. /**
  454. * Construct package list from IFR builder
  455. *
  456. * @v ifr IFR builder
  457. * @v guid Package GUID
  458. * @v language Language
  459. * @v language_id Language string ID
  460. * @ret package Package list, or NULL
  461. *
  462. * The package list is allocated using malloc(), and must eventually
  463. * be freed by the caller. (The caller must also call efi_ifr_free()
  464. * to free the temporary storage used during construction.)
  465. */
  466. EFI_HII_PACKAGE_LIST_HEADER * efi_ifr_package ( struct efi_ifr_builder *ifr,
  467. const EFI_GUID *guid,
  468. const char *language,
  469. unsigned int language_id ) {
  470. struct {
  471. EFI_HII_PACKAGE_LIST_HEADER header;
  472. struct {
  473. EFI_HII_PACKAGE_HEADER header;
  474. uint8_t data[ifr->ops_len];
  475. } __attribute__ (( packed )) ops;
  476. struct {
  477. union {
  478. EFI_HII_STRING_PACKAGE_HDR header;
  479. uint8_t pad[offsetof(EFI_HII_STRING_PACKAGE_HDR,
  480. Language) +
  481. strlen ( language ) + 1 /* NUL */ ];
  482. } __attribute__ (( packed )) header;
  483. uint8_t data[ifr->strings_len];
  484. EFI_HII_STRING_BLOCK end;
  485. } __attribute__ (( packed )) strings;
  486. EFI_HII_PACKAGE_HEADER end;
  487. } __attribute__ (( packed )) *package;
  488. /* Fail if any previous allocation failed */
  489. if ( ifr->failed )
  490. return NULL;
  491. /* Allocate package list */
  492. package = zalloc ( sizeof ( *package ) );
  493. if ( ! package )
  494. return NULL;
  495. /* Populate package list */
  496. package->header.PackageLength = sizeof ( *package );
  497. memcpy ( &package->header.PackageListGuid, guid,
  498. sizeof ( package->header.PackageListGuid ) );
  499. package->ops.header.Length = sizeof ( package->ops );
  500. package->ops.header.Type = EFI_HII_PACKAGE_FORMS;
  501. memcpy ( package->ops.data, ifr->ops, sizeof ( package->ops.data ) );
  502. package->strings.header.header.Header.Length =
  503. sizeof ( package->strings );
  504. package->strings.header.header.Header.Type =
  505. EFI_HII_PACKAGE_STRINGS;
  506. package->strings.header.header.HdrSize =
  507. sizeof ( package->strings.header );
  508. package->strings.header.header.StringInfoOffset =
  509. sizeof ( package->strings.header );
  510. package->strings.header.header.LanguageName = language_id;
  511. strcpy ( package->strings.header.header.Language, language );
  512. memcpy ( package->strings.data, ifr->strings,
  513. sizeof ( package->strings.data ) );
  514. package->strings.end.BlockType = EFI_HII_SIBT_END;
  515. package->end.Type = EFI_HII_PACKAGE_END;
  516. package->end.Length = sizeof ( package->end );
  517. return &package->header;
  518. }