123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /* vim: tabstop=4 shiftwidth=4 noexpandtab
- * This file is part of ToaruOS and is released under the terms
- * of the NCSA / University of Illinois License - see LICENSE.md
- * Copyright (C) 2018 K. Lange
- *
- * qemu-fwcfg - Read QEMU fwcfg values.
- *
- * Provides easy access to values and files set by QEMU's -fw_cfg
- * flag. This is used by the QEMU harness, as well as the bootloader,
- * and can be used to provide files directly to the guest.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <string.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <signal.h>
- #include <unistd.h>
- #include <fcntl.h>
- #define FW_CFG_PORT_OUT 0x510
- #define FW_CFG_PORT_IN 0x511
- #define FW_CFG_SELECT_QEMU 0x0000
- #define FW_CFG_SELECT_LIST 0x0019
- static int port_fd = -1;
- /* outw / inb helper functions */
- static void outports(unsigned short _port, unsigned short _data) {
- lseek(port_fd, _port, SEEK_SET);
- write(port_fd, &_data, 2);
- }
- static unsigned char inportb(unsigned short _port) {
- unsigned char out;
- lseek(port_fd, _port, SEEK_SET);
- read(port_fd, &out, 1);
- return out;
- }
- /* Despite primarily emulating x86, these are all big-endian */
- static void swap_bytes(void * in, int count) {
- char * bytes = in;
- if (count == 4) {
- uint32_t * t = in;
- *t = (bytes[0] << 24) | (bytes[1] << 12) | (bytes[2] << 8) | bytes[3];
- } else if (count == 2) {
- uint16_t * t = in;
- *t = (bytes[0] << 8) | bytes[1];
- }
- }
- /* Layout of the information returned from the fw_cfg port */
- struct fw_cfg_file {
- uint32_t size;
- uint16_t select;
- uint16_t reserved;
- char name[56];
- };
- static int usage(char * argv[]) {
- printf(
- "Obtain QEMU fw_cfg values\n"
- "\n"
- "usage: %s [-?ln] [config name]\n"
- "\n"
- " -l \033[3mlist available config entries\033[0m\n"
- " -n \033[3mdon't print a new line after data\033[0m\n"
- " -? \033[3mshow this help text\033[0m\n"
- "\n", argv[0]);
- return 1;
- }
- static void sig_pass(int sig) {
- exit(1);
- }
- int main(int argc, char * argv[]) {
- uint32_t count = 0;
- uint8_t * bytes = (uint8_t *)&count;
- int found = 0;
- struct fw_cfg_file file;
- uint8_t * tmp = (uint8_t *)&file;
- int opt = 0;
- int list = 0;
- int no_newline = 0;
- int query_quietly = 0;
- while ((opt = getopt(argc, argv, "?lnq")) != -1) {
- switch (opt) {
- case '?':
- return usage(argv);
- case 'n':
- no_newline = 1;
- break;
- case 'q':
- query_quietly = 1;
- break;
- case 'l':
- list = 1;
- break;
- }
- }
- if (optind >= argc && !list) {
- return usage(argv);
- }
- port_fd = open("/dev/port", O_RDWR);
- if (port_fd < 0) {
- fprintf(stderr, "%s: could not open port IO device\n", argv[0]);
- return 1;
- }
- signal(SIGILL, sig_pass);
- /* First check for QEMU */
- outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_QEMU);
- if (inportb(FW_CFG_PORT_IN) != 'Q' ||
- inportb(FW_CFG_PORT_IN) != 'E' ||
- inportb(FW_CFG_PORT_IN) != 'M' ||
- inportb(FW_CFG_PORT_IN) != 'U') {
- fprintf(stderr, "%s: this doesn't seem to be qemu\n", argv[0]);
- return 1;
- }
- /* Then get the list of "files" so we can look at names */
- outports(FW_CFG_PORT_OUT, FW_CFG_SELECT_LIST);
- for (int i = 0; i < 4; ++i) {
- bytes[i] = inportb(FW_CFG_PORT_IN);
- }
- swap_bytes(&count, sizeof(count));
- for (unsigned int i = 0; i < count; ++i) {
- /* read one file entry */
- for (unsigned int j = 0; j < sizeof(struct fw_cfg_file); ++j) {
- tmp[j] = inportb(FW_CFG_PORT_IN);
- }
- /* endian swap to get file size and selector ID */
- swap_bytes(&file.size, sizeof(file.size));
- swap_bytes(&file.select, sizeof(file.select));
- if (list) {
- /* 0x0020 org/whatever (1234 bytes) */
- fprintf(stdout, "0x%04x %s (%d byte%s)\n", file.select, file.name, (int)file.size, file.size == 1 ? "" : "s");
- } else {
- if (!strcmp(file.name, argv[optind])) {
- /* found the requested file */
- found = 1;
- break;
- }
- }
- }
- if (query_quietly) {
- return !found;
- }
- if (found) {
- /* if we found the requested file, read it from the port */
- outports(FW_CFG_PORT_OUT, file.select);
- for (unsigned int i = 0; i < file.size; ++i) {
- fputc(inportb(FW_CFG_PORT_IN), stdout);
- }
- if (!no_newline) {
- fprintf(stdout, "\n");
- } else {
- fflush(stdout);
- }
- } else if (!list) {
- fprintf(stderr, "%s: config option not found\n", argv[0]);
- return 1;
- }
- return 0;
- }
|