qemu-fwcfg.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * qemu-fwcfg - Read QEMU fwcfg values.
  7. *
  8. * Provides easy access to values and files set by QEMU's -fw_cfg
  9. * flag. This is used by the QEMU harness, as well as the bootloader,
  10. * and can be used to provide files directly to the guest.
  11. */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <stddef.h>
  15. #include <stdint.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include <getopt.h>
  19. #define FW_CFG_PORT_OUT 0x510
  20. #define FW_CFG_PORT_IN 0x511
  21. #define FW_CFG_SELECT_QEMU 0x0000
  22. #define FW_CFG_SELECT_LIST 0x0019
  23. /* outw / inb helper functions */
  24. static void outports(unsigned short _port, unsigned short _data) {
  25. asm volatile ("outw %1, %0" : : "dN" (_port), "a" (_data));
  26. }
  27. static unsigned char inportb(unsigned short _port) {
  28. unsigned char rv;
  29. asm volatile ("inb %1, %0" : "=a" (rv) : "dN" (_port));
  30. return rv;
  31. }
  32. /* Despite primarily emulating x86, these are all big-endian */
  33. static void swap_bytes(void * in, int count) {
  34. char * bytes = in;
  35. if (count == 4) {
  36. uint32_t * t = in;
  37. *t = (bytes[0] << 24) | (bytes[1] << 12) | (bytes[2] << 8) | bytes[3];
  38. } else if (count == 2) {
  39. uint16_t * t = in;
  40. *t = (bytes[0] << 8) | bytes[1];
  41. }
  42. }
  43. /* Layout of the information returned from the fw_cfg port */
  44. struct fw_cfg_file {
  45. uint32_t size;
  46. uint16_t select;
  47. uint16_t reserved;
  48. char name[56];
  49. };
  50. static int usage(char * argv[]) {
  51. printf(
  52. "Obtain QEMU fw_cfg values\n"
  53. "\n"
  54. "usage: %s [-?ln] [config name]\n"
  55. "\n"
  56. " -l \033[3mlist available config entries\033[0m\n"
  57. " -n \033[3mdon't print a new line after image\033[0m\n"
  58. " -? \033[3mshow this help text\033[0m\n"
  59. "\n", argv[0]);
  60. return 1;
  61. }
  62. int main(int argc, char * argv[]) {
  63. uint32_t count = 0;
  64. uint8_t * bytes = (uint8_t *)&count;
  65. int found = 0;
  66. struct fw_cfg_file file;
  67. uint8_t * tmp = (uint8_t *)&file;
  68. int opt = 0;
  69. int list = 0;
  70. int no_newline = 0;
  71. int query_quietly = 0;
  72. while ((opt = getopt(argc, argv, "?lnq")) != -1) {
  73. switch (opt) {
  74. case '?':
  75. return usage(argv);
  76. case 'n':
  77. no_newline = 1;
  78. break;
  79. case 'q':
  80. query_quietly = 1;
  81. break;
  82. case 'l':
  83. list = 1;
  84. break;
  85. }
  86. }
  87. if (optind >= argc && !list) {
  88. return usage(argv);
  89. }
  90. /* First check for QEMU */
  91. outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_QEMU);
  92. if (inportb(FW_CFG_PORT_IN) != 'Q' ||
  93. inportb(FW_CFG_PORT_IN) != 'E' ||
  94. inportb(FW_CFG_PORT_IN) != 'M' ||
  95. inportb(FW_CFG_PORT_IN) != 'U') {
  96. fprintf(stderr, "%s: this doesn't seem to be qemu\n", argv[0]);
  97. return 1;
  98. }
  99. /* Then get the list of "files" so we can look at names */
  100. outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_LIST);
  101. for (int i = 0; i < 4; ++i) {
  102. bytes[i] = inportb(FW_CFG_PORT_IN);
  103. }
  104. swap_bytes(&count, sizeof(count));
  105. for (unsigned int i = 0; i < count; ++i) {
  106. /* read one file entry */
  107. for (unsigned int j = 0; j < sizeof(struct fw_cfg_file); ++j) {
  108. tmp[j] = inportb(FW_CFG_PORT_IN);
  109. }
  110. /* endian swap to get file size and selector ID */
  111. swap_bytes(&file.size, sizeof(file.size));
  112. swap_bytes(&file.select, sizeof(file.select));
  113. if (list) {
  114. /* 0x0020 org/whatever (1234 bytes) */
  115. fprintf(stdout, "0x%04x %s (%d byte%s)\n", file.select, file.name, (int)file.size, file.size == 1 ? "" : "s");
  116. } else {
  117. if (!strcmp(file.name, argv[optind])) {
  118. /* found the requested file */
  119. found = 1;
  120. break;
  121. }
  122. }
  123. }
  124. if (query_quietly) {
  125. return !found;
  126. }
  127. if (found) {
  128. /* if we found the requested file, read it from the port */
  129. outports(FW_CFG_PORT_OUT, file.select);
  130. for (unsigned int i = 0; i < file.size; ++i) {
  131. fputc(inportb(FW_CFG_PORT_IN), stdout);
  132. }
  133. if (!no_newline) {
  134. fprintf(stdout, "\n");
  135. } else {
  136. fflush(stdout);
  137. }
  138. } else if (!list) {
  139. fprintf(stderr, "%s: config option not found\n", argv[0]);
  140. return 1;
  141. }
  142. return 0;
  143. }