efi_selftest_console.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * EFI efi_selftest
  3. *
  4. * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <efi_selftest.h>
  9. #include <vsprintf.h>
  10. struct efi_simple_text_output_protocol *con_out;
  11. struct efi_simple_input_interface *con_in;
  12. /*
  13. * Print a MAC address to an u16 string
  14. *
  15. * @pointer: mac address
  16. * @buf: pointer to buffer address
  17. * on return position of terminating zero word
  18. */
  19. static void mac(void *pointer, u16 **buf)
  20. {
  21. int i, j;
  22. u16 c;
  23. u8 *p = (u8 *)pointer;
  24. u8 byte;
  25. u16 *pos = *buf;
  26. for (i = 0; i < ARP_HLEN; ++i) {
  27. if (i)
  28. *pos++ = ':';
  29. byte = p[i];
  30. for (j = 4; j >= 0; j -= 4) {
  31. c = (byte >> j) & 0x0f;
  32. c += '0';
  33. if (c > '9')
  34. c += 'a' - '9' - 1;
  35. *pos++ = c;
  36. }
  37. }
  38. *pos = 0;
  39. *buf = pos;
  40. }
  41. /*
  42. * Print a pointer to an u16 string
  43. *
  44. * @pointer: pointer
  45. * @buf: pointer to buffer address
  46. * on return position of terminating zero word
  47. */
  48. static void pointer(void *pointer, u16 **buf)
  49. {
  50. int i;
  51. u16 c;
  52. uintptr_t p = (uintptr_t)pointer;
  53. u16 *pos = *buf;
  54. for (i = 8 * sizeof(p) - 4; i >= 0; i -= 4) {
  55. c = (p >> i) & 0x0f;
  56. c += '0';
  57. if (c > '9')
  58. c += 'a' - '9' - 1;
  59. *pos++ = c;
  60. }
  61. *pos = 0;
  62. *buf = pos;
  63. }
  64. /*
  65. * Print an unsigned 32bit value as decimal number to an u16 string
  66. *
  67. * @value: value to be printed
  68. * @buf: pointer to buffer address
  69. * on return position of terminating zero word
  70. */
  71. static void uint2dec(u32 value, u16 **buf)
  72. {
  73. u16 *pos = *buf;
  74. int i;
  75. u16 c;
  76. u64 f;
  77. /*
  78. * Increment by .5 and multiply with
  79. * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC
  80. * to move the first digit to bit 60-63.
  81. */
  82. f = 0x225C17D0;
  83. f += (0x9B5A52DULL * value) >> 28;
  84. f += 0x44B82FA0ULL * value;
  85. for (i = 0; i < 10; ++i) {
  86. /* Write current digit */
  87. c = f >> 60;
  88. if (c || pos != *buf)
  89. *pos++ = c + '0';
  90. /* Eliminate current digit */
  91. f &= 0xfffffffffffffff;
  92. /* Get next digit */
  93. f *= 0xaULL;
  94. }
  95. if (pos == *buf)
  96. *pos++ = '0';
  97. *pos = 0;
  98. *buf = pos;
  99. }
  100. /*
  101. * Print a signed 32bit value as decimal number to an u16 string
  102. *
  103. * @value: value to be printed
  104. * @buf: pointer to buffer address
  105. * on return position of terminating zero word
  106. */
  107. static void int2dec(s32 value, u16 **buf)
  108. {
  109. u32 u;
  110. u16 *pos = *buf;
  111. if (value < 0) {
  112. *pos++ = '-';
  113. u = -value;
  114. } else {
  115. u = value;
  116. }
  117. uint2dec(u, &pos);
  118. *buf = pos;
  119. }
  120. /*
  121. * Print a formatted string to the EFI console
  122. *
  123. * @fmt: format string
  124. * @...: optional arguments
  125. */
  126. void efi_st_printf(const char *fmt, ...)
  127. {
  128. va_list args;
  129. u16 buf[160];
  130. const char *c;
  131. u16 *pos = buf;
  132. const char *s;
  133. const u16 *u;
  134. va_start(args, fmt);
  135. c = fmt;
  136. for (; *c; ++c) {
  137. switch (*c) {
  138. case '\\':
  139. ++c;
  140. switch (*c) {
  141. case '\0':
  142. --c;
  143. break;
  144. case 'n':
  145. *pos++ = '\n';
  146. break;
  147. case 'r':
  148. *pos++ = '\r';
  149. break;
  150. case 't':
  151. *pos++ = '\t';
  152. break;
  153. default:
  154. *pos++ = *c;
  155. }
  156. break;
  157. case '%':
  158. ++c;
  159. switch (*c) {
  160. case '\0':
  161. --c;
  162. break;
  163. case 'd':
  164. int2dec(va_arg(args, s32), &pos);
  165. break;
  166. case 'p':
  167. ++c;
  168. switch (*c) {
  169. /* MAC address */
  170. case 'm':
  171. mac(va_arg(args, void*), &pos);
  172. break;
  173. /* u16 string */
  174. case 's':
  175. u = va_arg(args, u16*);
  176. /* Ensure string fits into buffer */
  177. for (; *u && pos < buf + 120; ++u)
  178. *pos++ = *u;
  179. break;
  180. default:
  181. --c;
  182. pointer(va_arg(args, void*), &pos);
  183. }
  184. break;
  185. case 's':
  186. s = va_arg(args, const char *);
  187. for (; *s; ++s)
  188. *pos++ = *s;
  189. break;
  190. case 'u':
  191. uint2dec(va_arg(args, u32), &pos);
  192. break;
  193. default:
  194. break;
  195. }
  196. break;
  197. default:
  198. *pos++ = *c;
  199. }
  200. }
  201. va_end(args);
  202. *pos = 0;
  203. con_out->output_string(con_out, buf);
  204. }
  205. /*
  206. * Reads an Unicode character from the input device.
  207. *
  208. * @return: Unicode character
  209. */
  210. u16 efi_st_get_key(void)
  211. {
  212. struct efi_input_key input_key;
  213. efi_status_t ret;
  214. /* Wait for next key */
  215. do {
  216. ret = con_in->read_key_stroke(con_in, &input_key);
  217. } while (ret == EFI_NOT_READY);
  218. return input_key.unicode_char;
  219. }