qemu-fwcfg.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. #include <signal.h>
  20. #include <unistd.h>
  21. #include <fcntl.h>
  22. #define FW_CFG_PORT_OUT 0x510
  23. #define FW_CFG_PORT_IN 0x511
  24. #define FW_CFG_SELECT_QEMU 0x0000
  25. #define FW_CFG_SELECT_LIST 0x0019
  26. static int port_fd = -1;
  27. /* outw / inb helper functions */
  28. static void outports(unsigned short _port, unsigned short _data) {
  29. lseek(port_fd, _port, SEEK_SET);
  30. write(port_fd, &_data, 2);
  31. }
  32. static unsigned char inportb(unsigned short _port) {
  33. unsigned char out;
  34. lseek(port_fd, _port, SEEK_SET);
  35. read(port_fd, &out, 1);
  36. return out;
  37. }
  38. /* Despite primarily emulating x86, these are all big-endian */
  39. static void swap_bytes(void * in, int count) {
  40. char * bytes = in;
  41. if (count == 4) {
  42. uint32_t * t = in;
  43. *t = (bytes[0] << 24) | (bytes[1] << 12) | (bytes[2] << 8) | bytes[3];
  44. } else if (count == 2) {
  45. uint16_t * t = in;
  46. *t = (bytes[0] << 8) | bytes[1];
  47. }
  48. }
  49. /* Layout of the information returned from the fw_cfg port */
  50. struct fw_cfg_file {
  51. uint32_t size;
  52. uint16_t select;
  53. uint16_t reserved;
  54. char name[56];
  55. };
  56. static int usage(char * argv[]) {
  57. printf(
  58. "Obtain QEMU fw_cfg values\n"
  59. "\n"
  60. "usage: %s [-?ln] [config name]\n"
  61. "\n"
  62. " -l \033[3mlist available config entries\033[0m\n"
  63. " -n \033[3mdon't print a new line after data\033[0m\n"
  64. " -? \033[3mshow this help text\033[0m\n"
  65. "\n", argv[0]);
  66. return 1;
  67. }
  68. static void sig_pass(int sig) {
  69. exit(1);
  70. }
  71. int main(int argc, char * argv[]) {
  72. uint32_t count = 0;
  73. uint8_t * bytes = (uint8_t *)&count;
  74. int found = 0;
  75. struct fw_cfg_file file;
  76. uint8_t * tmp = (uint8_t *)&file;
  77. int opt = 0;
  78. int list = 0;
  79. int no_newline = 0;
  80. int query_quietly = 0;
  81. while ((opt = getopt(argc, argv, "?lnq")) != -1) {
  82. switch (opt) {
  83. case '?':
  84. return usage(argv);
  85. case 'n':
  86. no_newline = 1;
  87. break;
  88. case 'q':
  89. query_quietly = 1;
  90. break;
  91. case 'l':
  92. list = 1;
  93. break;
  94. }
  95. }
  96. if (optind >= argc && !list) {
  97. return usage(argv);
  98. }
  99. port_fd = open("/dev/port", O_RDWR);
  100. if (port_fd < 0) {
  101. fprintf(stderr, "%s: could not open port IO device\n", argv[0]);
  102. return 1;
  103. }
  104. signal(SIGILL, sig_pass);
  105. /* First check for QEMU */
  106. outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_QEMU);
  107. if (inportb(FW_CFG_PORT_IN) != 'Q' ||
  108. inportb(FW_CFG_PORT_IN) != 'E' ||
  109. inportb(FW_CFG_PORT_IN) != 'M' ||
  110. inportb(FW_CFG_PORT_IN) != 'U') {
  111. fprintf(stderr, "%s: this doesn't seem to be qemu\n", argv[0]);
  112. return 1;
  113. }
  114. /* Then get the list of "files" so we can look at names */
  115. outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_LIST);
  116. for (int i = 0; i < 4; ++i) {
  117. bytes[i] = inportb(FW_CFG_PORT_IN);
  118. }
  119. swap_bytes(&count, sizeof(count));
  120. for (unsigned int i = 0; i < count; ++i) {
  121. /* read one file entry */
  122. for (unsigned int j = 0; j < sizeof(struct fw_cfg_file); ++j) {
  123. tmp[j] = inportb(FW_CFG_PORT_IN);
  124. }
  125. /* endian swap to get file size and selector ID */
  126. swap_bytes(&file.size, sizeof(file.size));
  127. swap_bytes(&file.select, sizeof(file.select));
  128. if (list) {
  129. /* 0x0020 org/whatever (1234 bytes) */
  130. fprintf(stdout, "0x%04x %s (%d byte%s)\n", file.select, file.name, (int)file.size, file.size == 1 ? "" : "s");
  131. } else {
  132. if (!strcmp(file.name, argv[optind])) {
  133. /* found the requested file */
  134. found = 1;
  135. break;
  136. }
  137. }
  138. }
  139. if (query_quietly) {
  140. return !found;
  141. }
  142. if (found) {
  143. /* if we found the requested file, read it from the port */
  144. outports(FW_CFG_PORT_OUT, file.select);
  145. for (unsigned int i = 0; i < file.size; ++i) {
  146. fputc(inportb(FW_CFG_PORT_IN), stdout);
  147. }
  148. if (!no_newline) {
  149. fprintf(stdout, "\n");
  150. } else {
  151. fflush(stdout);
  152. }
  153. } else if (!list) {
  154. fprintf(stderr, "%s: config option not found\n", argv[0]);
  155. return 1;
  156. }
  157. return 0;
  158. }