efi_hii.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * EFI Human Interface Infrastructure ... database and packages
  4. *
  5. * Copyright (c) 2017 Leif Lindholm
  6. * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
  7. */
  8. #include <common.h>
  9. #include <efi_loader.h>
  10. #include <malloc.h>
  11. #include <asm/unaligned.h>
  12. const efi_guid_t efi_guid_hii_database_protocol
  13. = EFI_HII_DATABASE_PROTOCOL_GUID;
  14. const efi_guid_t efi_guid_hii_string_protocol = EFI_HII_STRING_PROTOCOL_GUID;
  15. static LIST_HEAD(efi_package_lists);
  16. static LIST_HEAD(efi_keyboard_layout_list);
  17. struct efi_hii_packagelist {
  18. struct list_head link;
  19. // TODO should there be an associated efi_object?
  20. efi_handle_t driver_handle;
  21. u32 max_string_id;
  22. struct list_head string_tables; /* list of efi_string_table */
  23. struct list_head guid_list;
  24. struct list_head keyboard_packages;
  25. /* we could also track fonts, images, etc */
  26. };
  27. static int efi_hii_packagelist_exists(efi_hii_handle_t package_list)
  28. {
  29. struct efi_hii_packagelist *hii;
  30. int found = 0;
  31. list_for_each_entry(hii, &efi_package_lists, link) {
  32. if (hii == package_list) {
  33. found = 1;
  34. break;
  35. }
  36. }
  37. return found;
  38. }
  39. static u32 efi_hii_package_type(struct efi_hii_package_header *header)
  40. {
  41. u32 fields;
  42. fields = get_unaligned_le32(&header->fields);
  43. return (fields >> __EFI_HII_PACKAGE_TYPE_SHIFT)
  44. & __EFI_HII_PACKAGE_TYPE_MASK;
  45. }
  46. static u32 efi_hii_package_len(struct efi_hii_package_header *header)
  47. {
  48. u32 fields;
  49. fields = get_unaligned_le32(&header->fields);
  50. return (fields >> __EFI_HII_PACKAGE_LEN_SHIFT)
  51. & __EFI_HII_PACKAGE_LEN_MASK;
  52. }
  53. struct efi_string_info {
  54. efi_string_t string;
  55. /* we could also track font info, etc */
  56. };
  57. struct efi_string_table {
  58. struct list_head link;
  59. efi_string_id_t language_name;
  60. char *language;
  61. u32 nstrings;
  62. /*
  63. * NOTE:
  64. * string id starts at 1 so value is stbl->strings[id-1],
  65. * and strings[] is a array of stbl->nstrings elements
  66. */
  67. struct efi_string_info *strings;
  68. };
  69. struct efi_guid_data {
  70. struct list_head link;
  71. struct efi_hii_guid_package package;
  72. };
  73. struct efi_keyboard_layout_data {
  74. struct list_head link; /* in package */
  75. struct list_head link_sys; /* in global list */
  76. struct efi_hii_keyboard_layout keyboard_layout;
  77. };
  78. struct efi_keyboard_package_data {
  79. struct list_head link; /* in package_list */
  80. struct list_head keyboard_layout_list;
  81. };
  82. static void free_strings_table(struct efi_string_table *stbl)
  83. {
  84. int i;
  85. for (i = 0; i < stbl->nstrings; i++)
  86. free(stbl->strings[i].string);
  87. free(stbl->strings);
  88. free(stbl->language);
  89. free(stbl);
  90. }
  91. static void remove_strings_package(struct efi_hii_packagelist *hii)
  92. {
  93. while (!list_empty(&hii->string_tables)) {
  94. struct efi_string_table *stbl;
  95. stbl = list_first_entry(&hii->string_tables,
  96. struct efi_string_table, link);
  97. list_del(&stbl->link);
  98. free_strings_table(stbl);
  99. }
  100. }
  101. static efi_status_t
  102. add_strings_package(struct efi_hii_packagelist *hii,
  103. struct efi_hii_strings_package *strings_package)
  104. {
  105. struct efi_hii_string_block *block;
  106. void *end;
  107. u32 nstrings = 0, idx = 0;
  108. struct efi_string_table *stbl = NULL;
  109. efi_status_t ret;
  110. EFI_PRINT("header_size: %08x\n",
  111. get_unaligned_le32(&strings_package->header_size));
  112. EFI_PRINT("string_info_offset: %08x\n",
  113. get_unaligned_le32(&strings_package->string_info_offset));
  114. EFI_PRINT("language_name: %u\n",
  115. get_unaligned_le16(&strings_package->language_name));
  116. EFI_PRINT("language: %s\n", strings_package->language);
  117. /* count # of string entries: */
  118. end = ((void *)strings_package)
  119. + efi_hii_package_len(&strings_package->header);
  120. block = ((void *)strings_package)
  121. + get_unaligned_le32(&strings_package->string_info_offset);
  122. while ((void *)block < end) {
  123. switch (block->block_type) {
  124. case EFI_HII_SIBT_STRING_UCS2: {
  125. struct efi_hii_sibt_string_ucs2_block *ucs2;
  126. ucs2 = (void *)block;
  127. nstrings++;
  128. block = efi_hii_sibt_string_ucs2_block_next(ucs2);
  129. break;
  130. }
  131. case EFI_HII_SIBT_END:
  132. block = end;
  133. break;
  134. default:
  135. EFI_PRINT("unknown HII string block type: %02x\n",
  136. block->block_type);
  137. return EFI_INVALID_PARAMETER;
  138. }
  139. }
  140. stbl = calloc(sizeof(*stbl), 1);
  141. if (!stbl) {
  142. ret = EFI_OUT_OF_RESOURCES;
  143. goto error;
  144. }
  145. stbl->strings = calloc(sizeof(stbl->strings[0]), nstrings);
  146. if (!stbl->strings) {
  147. ret = EFI_OUT_OF_RESOURCES;
  148. goto error;
  149. }
  150. stbl->language_name =
  151. get_unaligned_le16(&strings_package->language_name);
  152. stbl->language = strdup((char *)strings_package->language);
  153. if (!stbl->language) {
  154. ret = EFI_OUT_OF_RESOURCES;
  155. goto error;
  156. }
  157. stbl->nstrings = nstrings;
  158. /* and now parse string entries and populate efi_string_table */
  159. block = ((void *)strings_package)
  160. + get_unaligned_le32(&strings_package->string_info_offset);
  161. while ((void *)block < end) {
  162. switch (block->block_type) {
  163. case EFI_HII_SIBT_STRING_UCS2: {
  164. struct efi_hii_sibt_string_ucs2_block *ucs2;
  165. ucs2 = (void *)block;
  166. EFI_PRINT("%4u: \"%ls\"\n", idx + 1, ucs2->string_text);
  167. stbl->strings[idx].string =
  168. u16_strdup(ucs2->string_text);
  169. if (!stbl->strings[idx].string) {
  170. ret = EFI_OUT_OF_RESOURCES;
  171. goto error;
  172. }
  173. idx++;
  174. /* FIXME: accessing u16 * here */
  175. block = efi_hii_sibt_string_ucs2_block_next(ucs2);
  176. break;
  177. }
  178. case EFI_HII_SIBT_END:
  179. goto out;
  180. default:
  181. EFI_PRINT("unknown HII string block type: %02x\n",
  182. block->block_type);
  183. ret = EFI_INVALID_PARAMETER;
  184. goto error;
  185. }
  186. }
  187. out:
  188. list_add(&stbl->link, &hii->string_tables);
  189. if (hii->max_string_id < nstrings)
  190. hii->max_string_id = nstrings;
  191. return EFI_SUCCESS;
  192. error:
  193. if (stbl) {
  194. free(stbl->language);
  195. while (idx > 0)
  196. free(stbl->strings[--idx].string);
  197. free(stbl->strings);
  198. }
  199. free(stbl);
  200. return ret;
  201. }
  202. static void remove_guid_package(struct efi_hii_packagelist *hii)
  203. {
  204. struct efi_guid_data *data;
  205. while (!list_empty(&hii->guid_list)) {
  206. data = list_first_entry(&hii->guid_list,
  207. struct efi_guid_data, link);
  208. list_del(&data->link);
  209. free(data);
  210. }
  211. }
  212. static efi_status_t
  213. add_guid_package(struct efi_hii_packagelist *hii,
  214. struct efi_hii_guid_package *package)
  215. {
  216. struct efi_guid_data *data;
  217. data = calloc(sizeof(*data), 1);
  218. if (!data)
  219. return EFI_OUT_OF_RESOURCES;
  220. /* TODO: we don't know any about data field */
  221. memcpy(&data->package, package, sizeof(*package));
  222. list_add_tail(&data->link, &hii->guid_list);
  223. return EFI_SUCCESS;
  224. }
  225. static void free_keyboard_layouts(struct efi_keyboard_package_data *package)
  226. {
  227. struct efi_keyboard_layout_data *layout_data;
  228. while (!list_empty(&package->keyboard_layout_list)) {
  229. layout_data = list_first_entry(&package->keyboard_layout_list,
  230. struct efi_keyboard_layout_data,
  231. link);
  232. list_del(&layout_data->link);
  233. list_del(&layout_data->link_sys);
  234. free(layout_data);
  235. }
  236. }
  237. static void remove_keyboard_package(struct efi_hii_packagelist *hii)
  238. {
  239. struct efi_keyboard_package_data *package;
  240. while (!list_empty(&hii->keyboard_packages)) {
  241. package = list_first_entry(&hii->keyboard_packages,
  242. struct efi_keyboard_package_data,
  243. link);
  244. free_keyboard_layouts(package);
  245. list_del(&package->link);
  246. free(package);
  247. }
  248. }
  249. static efi_status_t
  250. add_keyboard_package(struct efi_hii_packagelist *hii,
  251. struct efi_hii_keyboard_package *keyboard_package)
  252. {
  253. struct efi_keyboard_package_data *package_data;
  254. struct efi_hii_keyboard_layout *layout;
  255. struct efi_keyboard_layout_data *layout_data;
  256. u16 layout_count, layout_length;
  257. int i;
  258. package_data = malloc(sizeof(*package_data));
  259. if (!package_data)
  260. return EFI_OUT_OF_RESOURCES;
  261. INIT_LIST_HEAD(&package_data->link);
  262. INIT_LIST_HEAD(&package_data->keyboard_layout_list);
  263. layout = &keyboard_package->layout[0];
  264. layout_count = get_unaligned_le16(&keyboard_package->layout_count);
  265. for (i = 0; i < layout_count; i++) {
  266. layout_length = get_unaligned_le16(&layout->layout_length);
  267. layout_data = malloc(sizeof(*layout_data) + layout_length);
  268. if (!layout_data)
  269. goto out;
  270. memcpy(&layout_data->keyboard_layout, layout, layout_length);
  271. list_add_tail(&layout_data->link,
  272. &package_data->keyboard_layout_list);
  273. list_add_tail(&layout_data->link_sys,
  274. &efi_keyboard_layout_list);
  275. layout += layout_length;
  276. }
  277. list_add_tail(&package_data->link, &hii->keyboard_packages);
  278. return EFI_SUCCESS;
  279. out:
  280. free_keyboard_layouts(package_data);
  281. free(package_data);
  282. return EFI_OUT_OF_RESOURCES;
  283. }
  284. static struct efi_hii_packagelist *new_packagelist(void)
  285. {
  286. struct efi_hii_packagelist *hii;
  287. hii = malloc(sizeof(*hii));
  288. list_add_tail(&hii->link, &efi_package_lists);
  289. hii->max_string_id = 0;
  290. INIT_LIST_HEAD(&hii->string_tables);
  291. INIT_LIST_HEAD(&hii->guid_list);
  292. INIT_LIST_HEAD(&hii->keyboard_packages);
  293. return hii;
  294. }
  295. static void free_packagelist(struct efi_hii_packagelist *hii)
  296. {
  297. remove_strings_package(hii);
  298. remove_guid_package(hii);
  299. remove_keyboard_package(hii);
  300. list_del(&hii->link);
  301. free(hii);
  302. }
  303. static efi_status_t
  304. add_packages(struct efi_hii_packagelist *hii,
  305. const struct efi_hii_package_list_header *package_list)
  306. {
  307. struct efi_hii_package_header *package;
  308. void *end;
  309. efi_status_t ret = EFI_SUCCESS;
  310. end = ((void *)package_list)
  311. + get_unaligned_le32(&package_list->package_length);
  312. EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
  313. get_unaligned_le32(&package_list->package_length));
  314. package = ((void *)package_list) + sizeof(*package_list);
  315. while ((void *)package < end) {
  316. EFI_PRINT("package=%p, package type=%x, length=%u\n", package,
  317. efi_hii_package_type(package),
  318. efi_hii_package_len(package));
  319. switch (efi_hii_package_type(package)) {
  320. case EFI_HII_PACKAGE_TYPE_GUID:
  321. ret = add_guid_package(hii,
  322. (struct efi_hii_guid_package *)package);
  323. break;
  324. case EFI_HII_PACKAGE_FORMS:
  325. EFI_PRINT("Form package not supported\n");
  326. ret = EFI_INVALID_PARAMETER;
  327. break;
  328. case EFI_HII_PACKAGE_STRINGS:
  329. ret = add_strings_package(hii,
  330. (struct efi_hii_strings_package *)package);
  331. break;
  332. case EFI_HII_PACKAGE_FONTS:
  333. EFI_PRINT("Font package not supported\n");
  334. ret = EFI_INVALID_PARAMETER;
  335. break;
  336. case EFI_HII_PACKAGE_IMAGES:
  337. EFI_PRINT("Image package not supported\n");
  338. ret = EFI_INVALID_PARAMETER;
  339. break;
  340. case EFI_HII_PACKAGE_SIMPLE_FONTS:
  341. EFI_PRINT("Simple font package not supported\n");
  342. ret = EFI_INVALID_PARAMETER;
  343. break;
  344. case EFI_HII_PACKAGE_DEVICE_PATH:
  345. EFI_PRINT("Device path package not supported\n");
  346. ret = EFI_INVALID_PARAMETER;
  347. break;
  348. case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
  349. ret = add_keyboard_package(hii,
  350. (struct efi_hii_keyboard_package *)package);
  351. break;
  352. case EFI_HII_PACKAGE_ANIMATIONS:
  353. EFI_PRINT("Animation package not supported\n");
  354. ret = EFI_INVALID_PARAMETER;
  355. break;
  356. case EFI_HII_PACKAGE_END:
  357. goto out;
  358. case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
  359. case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
  360. default:
  361. break;
  362. }
  363. if (ret != EFI_SUCCESS)
  364. return ret;
  365. package = (void *)package + efi_hii_package_len(package);
  366. }
  367. out:
  368. // TODO in theory there is some notifications that should be sent..
  369. return EFI_SUCCESS;
  370. }
  371. /*
  372. * EFI_HII_DATABASE_PROTOCOL
  373. */
  374. static efi_status_t EFIAPI
  375. new_package_list(const struct efi_hii_database_protocol *this,
  376. const struct efi_hii_package_list_header *package_list,
  377. const efi_handle_t driver_handle,
  378. efi_hii_handle_t *handle)
  379. {
  380. struct efi_hii_packagelist *hii;
  381. efi_status_t ret;
  382. EFI_ENTRY("%p, %p, %p, %p", this, package_list, driver_handle, handle);
  383. if (!package_list || !handle)
  384. return EFI_EXIT(EFI_INVALID_PARAMETER);
  385. hii = new_packagelist();
  386. if (!hii)
  387. return EFI_EXIT(EFI_OUT_OF_RESOURCES);
  388. ret = add_packages(hii, package_list);
  389. if (ret != EFI_SUCCESS) {
  390. free_packagelist(hii);
  391. return EFI_EXIT(ret);
  392. }
  393. hii->driver_handle = driver_handle;
  394. *handle = hii;
  395. return EFI_EXIT(EFI_SUCCESS);
  396. }
  397. static efi_status_t EFIAPI
  398. remove_package_list(const struct efi_hii_database_protocol *this,
  399. efi_hii_handle_t handle)
  400. {
  401. struct efi_hii_packagelist *hii = handle;
  402. EFI_ENTRY("%p, %p", this, handle);
  403. if (!handle || !efi_hii_packagelist_exists(handle))
  404. return EFI_EXIT(EFI_NOT_FOUND);
  405. free_packagelist(hii);
  406. return EFI_EXIT(EFI_SUCCESS);
  407. }
  408. static efi_status_t EFIAPI
  409. update_package_list(const struct efi_hii_database_protocol *this,
  410. efi_hii_handle_t handle,
  411. const struct efi_hii_package_list_header *package_list)
  412. {
  413. struct efi_hii_packagelist *hii = handle;
  414. struct efi_hii_package_header *package;
  415. void *end;
  416. efi_status_t ret = EFI_SUCCESS;
  417. EFI_ENTRY("%p, %p, %p", this, handle, package_list);
  418. if (!handle || !efi_hii_packagelist_exists(handle))
  419. return EFI_EXIT(EFI_NOT_FOUND);
  420. if (!package_list)
  421. return EFI_EXIT(EFI_INVALID_PARAMETER);
  422. EFI_PRINT("package_list: %pUl (%u)\n", &package_list->package_list_guid,
  423. get_unaligned_le32(&package_list->package_length));
  424. package = ((void *)package_list) + sizeof(*package_list);
  425. end = ((void *)package_list)
  426. + get_unaligned_le32(&package_list->package_length);
  427. while ((void *)package < end) {
  428. EFI_PRINT("package=%p, package type=%x, length=%u\n", package,
  429. efi_hii_package_type(package),
  430. efi_hii_package_len(package));
  431. switch (efi_hii_package_type(package)) {
  432. case EFI_HII_PACKAGE_TYPE_GUID:
  433. remove_guid_package(hii);
  434. break;
  435. case EFI_HII_PACKAGE_FORMS:
  436. EFI_PRINT("Form package not supported\n");
  437. ret = EFI_INVALID_PARAMETER;
  438. break;
  439. case EFI_HII_PACKAGE_STRINGS:
  440. remove_strings_package(hii);
  441. break;
  442. case EFI_HII_PACKAGE_FONTS:
  443. EFI_PRINT("Font package not supported\n");
  444. ret = EFI_INVALID_PARAMETER;
  445. break;
  446. case EFI_HII_PACKAGE_IMAGES:
  447. EFI_PRINT("Image package not supported\n");
  448. ret = EFI_INVALID_PARAMETER;
  449. break;
  450. case EFI_HII_PACKAGE_SIMPLE_FONTS:
  451. EFI_PRINT("Simple font package not supported\n");
  452. ret = EFI_INVALID_PARAMETER;
  453. break;
  454. case EFI_HII_PACKAGE_DEVICE_PATH:
  455. EFI_PRINT("Device path package not supported\n");
  456. ret = EFI_INVALID_PARAMETER;
  457. break;
  458. case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
  459. remove_keyboard_package(hii);
  460. break;
  461. case EFI_HII_PACKAGE_ANIMATIONS:
  462. EFI_PRINT("Animation package not supported\n");
  463. ret = EFI_INVALID_PARAMETER;
  464. break;
  465. case EFI_HII_PACKAGE_END:
  466. goto out;
  467. case EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN:
  468. case EFI_HII_PACKAGE_TYPE_SYSTEM_END:
  469. default:
  470. break;
  471. }
  472. /* TODO: already removed some packages */
  473. if (ret != EFI_SUCCESS)
  474. return EFI_EXIT(ret);
  475. package = ((void *)package)
  476. + efi_hii_package_len(package);
  477. }
  478. out:
  479. ret = add_packages(hii, package_list);
  480. return EFI_EXIT(ret);
  481. }
  482. static efi_status_t EFIAPI
  483. list_package_lists(const struct efi_hii_database_protocol *this,
  484. u8 package_type,
  485. const efi_guid_t *package_guid,
  486. efi_uintn_t *handle_buffer_length,
  487. efi_hii_handle_t *handle)
  488. {
  489. struct efi_hii_packagelist *hii =
  490. (struct efi_hii_packagelist *)handle;
  491. int package_cnt, package_max;
  492. efi_status_t ret = EFI_NOT_FOUND;
  493. EFI_ENTRY("%p, %u, %pUl, %p, %p", this, package_type, package_guid,
  494. handle_buffer_length, handle);
  495. if (!handle_buffer_length ||
  496. (*handle_buffer_length && !handle)) {
  497. ret = EFI_INVALID_PARAMETER;
  498. goto out;
  499. }
  500. if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
  501. (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid)) {
  502. ret = EFI_INVALID_PARAMETER;
  503. goto out;
  504. }
  505. EFI_PRINT("package type=%x, guid=%pUl, length=%zu\n", (int)package_type,
  506. package_guid, *handle_buffer_length);
  507. package_cnt = 0;
  508. package_max = *handle_buffer_length / sizeof(*handle);
  509. list_for_each_entry(hii, &efi_package_lists, link) {
  510. switch (package_type) {
  511. case EFI_HII_PACKAGE_TYPE_ALL:
  512. break;
  513. case EFI_HII_PACKAGE_TYPE_GUID:
  514. if (!list_empty(&hii->guid_list))
  515. break;
  516. continue;
  517. case EFI_HII_PACKAGE_STRINGS:
  518. if (!list_empty(&hii->string_tables))
  519. break;
  520. continue;
  521. case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
  522. if (!list_empty(&hii->keyboard_packages))
  523. break;
  524. continue;
  525. default:
  526. continue;
  527. }
  528. package_cnt++;
  529. if (package_cnt <= package_max) {
  530. *handle++ = hii;
  531. ret = EFI_SUCCESS;
  532. } else {
  533. ret = EFI_BUFFER_TOO_SMALL;
  534. }
  535. }
  536. *handle_buffer_length = package_cnt * sizeof(*handle);
  537. out:
  538. return EFI_EXIT(ret);
  539. }
  540. static efi_status_t EFIAPI
  541. export_package_lists(const struct efi_hii_database_protocol *this,
  542. efi_hii_handle_t handle,
  543. efi_uintn_t *buffer_size,
  544. struct efi_hii_package_list_header *buffer)
  545. {
  546. EFI_ENTRY("%p, %p, %p, %p", this, handle, buffer_size, buffer);
  547. if (!buffer_size || !buffer)
  548. return EFI_EXIT(EFI_INVALID_PARAMETER);
  549. return EFI_EXIT(EFI_NOT_FOUND);
  550. }
  551. static efi_status_t EFIAPI
  552. register_package_notify(const struct efi_hii_database_protocol *this,
  553. u8 package_type,
  554. const efi_guid_t *package_guid,
  555. const void *package_notify_fn,
  556. efi_uintn_t notify_type,
  557. efi_handle_t *notify_handle)
  558. {
  559. EFI_ENTRY("%p, %u, %pUl, %p, %zu, %p", this, package_type,
  560. package_guid, package_notify_fn, notify_type,
  561. notify_handle);
  562. if (!notify_handle)
  563. return EFI_EXIT(EFI_INVALID_PARAMETER);
  564. if ((package_type != EFI_HII_PACKAGE_TYPE_GUID && package_guid) ||
  565. (package_type == EFI_HII_PACKAGE_TYPE_GUID && !package_guid))
  566. return EFI_EXIT(EFI_INVALID_PARAMETER);
  567. return EFI_EXIT(EFI_OUT_OF_RESOURCES);
  568. }
  569. static efi_status_t EFIAPI
  570. unregister_package_notify(const struct efi_hii_database_protocol *this,
  571. efi_handle_t notification_handle)
  572. {
  573. EFI_ENTRY("%p, %p", this, notification_handle);
  574. return EFI_EXIT(EFI_NOT_FOUND);
  575. }
  576. static efi_status_t EFIAPI
  577. find_keyboard_layouts(const struct efi_hii_database_protocol *this,
  578. u16 *key_guid_buffer_length,
  579. efi_guid_t *key_guid_buffer)
  580. {
  581. struct efi_keyboard_layout_data *layout_data;
  582. int package_cnt, package_max;
  583. efi_status_t ret = EFI_SUCCESS;
  584. EFI_ENTRY("%p, %p, %p", this, key_guid_buffer_length, key_guid_buffer);
  585. if (!key_guid_buffer_length ||
  586. (*key_guid_buffer_length && !key_guid_buffer))
  587. return EFI_EXIT(EFI_INVALID_PARAMETER);
  588. package_cnt = 0;
  589. package_max = *key_guid_buffer_length / sizeof(*key_guid_buffer);
  590. list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
  591. package_cnt++;
  592. if (package_cnt <= package_max)
  593. memcpy(key_guid_buffer++,
  594. &layout_data->keyboard_layout.guid,
  595. sizeof(*key_guid_buffer));
  596. else
  597. ret = EFI_BUFFER_TOO_SMALL;
  598. }
  599. *key_guid_buffer_length = package_cnt * sizeof(*key_guid_buffer);
  600. return EFI_EXIT(ret);
  601. }
  602. static efi_status_t EFIAPI
  603. get_keyboard_layout(const struct efi_hii_database_protocol *this,
  604. efi_guid_t *key_guid,
  605. u16 *keyboard_layout_length,
  606. struct efi_hii_keyboard_layout *keyboard_layout)
  607. {
  608. struct efi_keyboard_layout_data *layout_data;
  609. u16 layout_length;
  610. EFI_ENTRY("%p, %pUl, %p, %p", this, key_guid, keyboard_layout_length,
  611. keyboard_layout);
  612. if (!keyboard_layout_length ||
  613. (*keyboard_layout_length && !keyboard_layout))
  614. return EFI_EXIT(EFI_INVALID_PARAMETER);
  615. /* TODO: no notion of current keyboard layout */
  616. if (!key_guid)
  617. return EFI_EXIT(EFI_INVALID_PARAMETER);
  618. list_for_each_entry(layout_data, &efi_keyboard_layout_list, link_sys) {
  619. if (!guidcmp(&layout_data->keyboard_layout.guid, key_guid))
  620. goto found;
  621. }
  622. return EFI_EXIT(EFI_NOT_FOUND);
  623. found:
  624. layout_length =
  625. get_unaligned_le16(&layout_data->keyboard_layout.layout_length);
  626. if (*keyboard_layout_length < layout_length) {
  627. *keyboard_layout_length = layout_length;
  628. return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
  629. }
  630. memcpy(keyboard_layout, &layout_data->keyboard_layout, layout_length);
  631. return EFI_EXIT(EFI_SUCCESS);
  632. }
  633. static efi_status_t EFIAPI
  634. set_keyboard_layout(const struct efi_hii_database_protocol *this,
  635. efi_guid_t *key_guid)
  636. {
  637. EFI_ENTRY("%p, %pUl", this, key_guid);
  638. return EFI_EXIT(EFI_NOT_FOUND);
  639. }
  640. static efi_status_t EFIAPI
  641. get_package_list_handle(const struct efi_hii_database_protocol *this,
  642. efi_hii_handle_t package_list_handle,
  643. efi_handle_t *driver_handle)
  644. {
  645. struct efi_hii_packagelist *hii;
  646. EFI_ENTRY("%p, %p, %p", this, package_list_handle, driver_handle);
  647. if (!driver_handle)
  648. return EFI_EXIT(EFI_INVALID_PARAMETER);
  649. list_for_each_entry(hii, &efi_package_lists, link) {
  650. if (hii == package_list_handle) {
  651. *driver_handle = hii->driver_handle;
  652. return EFI_EXIT(EFI_SUCCESS);
  653. }
  654. }
  655. return EFI_EXIT(EFI_NOT_FOUND);
  656. }
  657. const struct efi_hii_database_protocol efi_hii_database = {
  658. .new_package_list = new_package_list,
  659. .remove_package_list = remove_package_list,
  660. .update_package_list = update_package_list,
  661. .list_package_lists = list_package_lists,
  662. .export_package_lists = export_package_lists,
  663. .register_package_notify = register_package_notify,
  664. .unregister_package_notify = unregister_package_notify,
  665. .find_keyboard_layouts = find_keyboard_layouts,
  666. .get_keyboard_layout = get_keyboard_layout,
  667. .set_keyboard_layout = set_keyboard_layout,
  668. .get_package_list_handle = get_package_list_handle
  669. };
  670. /*
  671. * EFI_HII_STRING_PROTOCOL
  672. */
  673. static bool language_match(char *language, char *languages)
  674. {
  675. size_t n;
  676. n = strlen(language);
  677. /* match primary language? */
  678. if (!strncasecmp(language, languages, n) &&
  679. (languages[n] == ';' || languages[n] == '\0'))
  680. return true;
  681. return false;
  682. }
  683. static efi_status_t EFIAPI
  684. new_string(const struct efi_hii_string_protocol *this,
  685. efi_hii_handle_t package_list,
  686. efi_string_id_t *string_id,
  687. const u8 *language,
  688. const u16 *language_name,
  689. const efi_string_t string,
  690. const struct efi_font_info *string_font_info)
  691. {
  692. struct efi_hii_packagelist *hii = package_list;
  693. struct efi_string_table *stbl;
  694. EFI_ENTRY("%p, %p, %p, \"%s\", %p, \"%ls\", %p", this, package_list,
  695. string_id, language, language_name, string,
  696. string_font_info);
  697. if (!package_list || !efi_hii_packagelist_exists(package_list))
  698. return EFI_EXIT(EFI_NOT_FOUND);
  699. if (!string_id || !language || !string)
  700. return EFI_EXIT(EFI_INVALID_PARAMETER);
  701. list_for_each_entry(stbl, &hii->string_tables, link) {
  702. if (language_match((char *)language, stbl->language)) {
  703. efi_string_id_t new_id;
  704. void *buf;
  705. efi_string_t str;
  706. new_id = ++hii->max_string_id;
  707. if (stbl->nstrings < new_id) {
  708. buf = realloc(stbl->strings,
  709. sizeof(stbl->strings[0])
  710. * new_id);
  711. if (!buf)
  712. return EFI_EXIT(EFI_OUT_OF_RESOURCES);
  713. memset(&stbl->strings[stbl->nstrings], 0,
  714. (new_id - stbl->nstrings)
  715. * sizeof(stbl->strings[0]));
  716. stbl->strings = buf;
  717. stbl->nstrings = new_id;
  718. }
  719. str = u16_strdup(string);
  720. if (!str)
  721. return EFI_EXIT(EFI_OUT_OF_RESOURCES);
  722. stbl->strings[new_id - 1].string = str;
  723. *string_id = new_id;
  724. return EFI_EXIT(EFI_SUCCESS);
  725. }
  726. }
  727. return EFI_EXIT(EFI_NOT_FOUND);
  728. }
  729. static efi_status_t EFIAPI
  730. get_string(const struct efi_hii_string_protocol *this,
  731. const u8 *language,
  732. efi_hii_handle_t package_list,
  733. efi_string_id_t string_id,
  734. efi_string_t string,
  735. efi_uintn_t *string_size,
  736. struct efi_font_info **string_font_info)
  737. {
  738. struct efi_hii_packagelist *hii = package_list;
  739. struct efi_string_table *stbl;
  740. EFI_ENTRY("%p, \"%s\", %p, %u, %p, %p, %p", this, language,
  741. package_list, string_id, string, string_size,
  742. string_font_info);
  743. if (!package_list || !efi_hii_packagelist_exists(package_list))
  744. return EFI_EXIT(EFI_NOT_FOUND);
  745. list_for_each_entry(stbl, &hii->string_tables, link) {
  746. if (language_match((char *)language, stbl->language)) {
  747. efi_string_t str;
  748. size_t len;
  749. if (stbl->nstrings < string_id)
  750. return EFI_EXIT(EFI_NOT_FOUND);
  751. str = stbl->strings[string_id - 1].string;
  752. if (str) {
  753. len = (u16_strlen(str) + 1) * sizeof(u16);
  754. if (*string_size < len) {
  755. *string_size = len;
  756. return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
  757. }
  758. memcpy(string, str, len);
  759. *string_size = len;
  760. } else {
  761. return EFI_EXIT(EFI_NOT_FOUND);
  762. }
  763. return EFI_EXIT(EFI_SUCCESS);
  764. }
  765. }
  766. return EFI_EXIT(EFI_NOT_FOUND);
  767. }
  768. static efi_status_t EFIAPI
  769. set_string(const struct efi_hii_string_protocol *this,
  770. efi_hii_handle_t package_list,
  771. efi_string_id_t string_id,
  772. const u8 *language,
  773. const efi_string_t string,
  774. const struct efi_font_info *string_font_info)
  775. {
  776. struct efi_hii_packagelist *hii = package_list;
  777. struct efi_string_table *stbl;
  778. EFI_ENTRY("%p, %p, %u, \"%s\", \"%ls\", %p", this, package_list,
  779. string_id, language, string, string_font_info);
  780. if (!package_list || !efi_hii_packagelist_exists(package_list))
  781. return EFI_EXIT(EFI_NOT_FOUND);
  782. if (string_id > hii->max_string_id)
  783. return EFI_EXIT(EFI_NOT_FOUND);
  784. if (!string || !language)
  785. return EFI_EXIT(EFI_INVALID_PARAMETER);
  786. list_for_each_entry(stbl, &hii->string_tables, link) {
  787. if (language_match((char *)language, stbl->language)) {
  788. efi_string_t str;
  789. if (hii->max_string_id < string_id)
  790. return EFI_EXIT(EFI_NOT_FOUND);
  791. if (stbl->nstrings < string_id) {
  792. void *buf;
  793. buf = realloc(stbl->strings,
  794. string_id
  795. * sizeof(stbl->strings[0]));
  796. if (!buf)
  797. return EFI_EXIT(EFI_OUT_OF_RESOURCES);
  798. memset(&stbl->strings[string_id - 1], 0,
  799. (string_id - stbl->nstrings)
  800. * sizeof(stbl->strings[0]));
  801. stbl->strings = buf;
  802. }
  803. str = u16_strdup(string);
  804. if (!str)
  805. return EFI_EXIT(EFI_OUT_OF_RESOURCES);
  806. free(stbl->strings[string_id - 1].string);
  807. stbl->strings[string_id - 1].string = str;
  808. return EFI_EXIT(EFI_SUCCESS);
  809. }
  810. }
  811. return EFI_EXIT(EFI_NOT_FOUND);
  812. }
  813. static efi_status_t EFIAPI
  814. get_languages(const struct efi_hii_string_protocol *this,
  815. efi_hii_handle_t package_list,
  816. u8 *languages,
  817. efi_uintn_t *languages_size)
  818. {
  819. struct efi_hii_packagelist *hii = package_list;
  820. struct efi_string_table *stbl;
  821. size_t len = 0;
  822. char *p;
  823. EFI_ENTRY("%p, %p, %p, %p", this, package_list, languages,
  824. languages_size);
  825. if (!package_list || !efi_hii_packagelist_exists(package_list))
  826. return EFI_EXIT(EFI_NOT_FOUND);
  827. if (!languages_size ||
  828. (*languages_size && !languages))
  829. return EFI_EXIT(EFI_INVALID_PARAMETER);
  830. /* figure out required size: */
  831. list_for_each_entry(stbl, &hii->string_tables, link) {
  832. len += strlen((char *)stbl->language) + 1;
  833. }
  834. if (*languages_size < len) {
  835. *languages_size = len;
  836. return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
  837. }
  838. p = (char *)languages;
  839. list_for_each_entry(stbl, &hii->string_tables, link) {
  840. if (p != (char *)languages)
  841. *p++ = ';';
  842. strcpy(p, stbl->language);
  843. p += strlen((char *)stbl->language);
  844. }
  845. *p = '\0';
  846. EFI_PRINT("languages: %s\n", languages);
  847. return EFI_EXIT(EFI_SUCCESS);
  848. }
  849. static efi_status_t EFIAPI
  850. get_secondary_languages(const struct efi_hii_string_protocol *this,
  851. efi_hii_handle_t package_list,
  852. const u8 *primary_language,
  853. u8 *secondary_languages,
  854. efi_uintn_t *secondary_languages_size)
  855. {
  856. struct efi_hii_packagelist *hii = package_list;
  857. struct efi_string_table *stbl;
  858. bool found = false;
  859. EFI_ENTRY("%p, %p, \"%s\", %p, %p", this, package_list,
  860. primary_language, secondary_languages,
  861. secondary_languages_size);
  862. if (!package_list || !efi_hii_packagelist_exists(package_list))
  863. return EFI_EXIT(EFI_NOT_FOUND);
  864. if (!secondary_languages_size ||
  865. (*secondary_languages_size && !secondary_languages))
  866. return EFI_EXIT(EFI_INVALID_PARAMETER);
  867. list_for_each_entry(stbl, &hii->string_tables, link) {
  868. if (language_match((char *)primary_language, stbl->language)) {
  869. found = true;
  870. break;
  871. }
  872. }
  873. if (!found)
  874. return EFI_EXIT(EFI_INVALID_LANGUAGE);
  875. /*
  876. * TODO: What is secondary language?
  877. * *secondary_languages = '\0';
  878. * *secondary_languages_size = 0;
  879. */
  880. return EFI_EXIT(EFI_NOT_FOUND);
  881. }
  882. const struct efi_hii_string_protocol efi_hii_string = {
  883. .new_string = new_string,
  884. .get_string = get_string,
  885. .set_string = set_string,
  886. .get_languages = get_languages,
  887. .get_secondary_languages = get_secondary_languages
  888. };