1 /* 2 * libqos fw_cfg support 3 * 4 * Copyright IBM, Corp. 2012-2013 5 * Copyright (C) 2013 Red Hat Inc. 6 * 7 * Authors: 8 * Anthony Liguori <aliguori@us.ibm.com> 9 * Markus Armbruster <armbru@redhat.com> 10 * 11 * This work is licensed under the terms of the GNU GPL, version 2 or later. 12 * See the COPYING file in the top-level directory. 13 */ 14 15 #include "qemu/osdep.h" 16 #include "fw_cfg.h" 17 #include "../libqtest.h" 18 #include "qemu/bswap.h" 19 #include "hw/nvram/fw_cfg.h" 20 21 void qfw_cfg_select(QFWCFG *fw_cfg, uint16_t key) 22 { 23 fw_cfg->select(fw_cfg, key); 24 } 25 26 void qfw_cfg_read_data(QFWCFG *fw_cfg, void *data, size_t len) 27 { 28 fw_cfg->read(fw_cfg, data, len); 29 } 30 31 void qfw_cfg_get(QFWCFG *fw_cfg, uint16_t key, void *data, size_t len) 32 { 33 qfw_cfg_select(fw_cfg, key); 34 qfw_cfg_read_data(fw_cfg, data, len); 35 } 36 37 uint16_t qfw_cfg_get_u16(QFWCFG *fw_cfg, uint16_t key) 38 { 39 uint16_t value; 40 qfw_cfg_get(fw_cfg, key, &value, sizeof(value)); 41 return le16_to_cpu(value); 42 } 43 44 uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key) 45 { 46 uint32_t value; 47 qfw_cfg_get(fw_cfg, key, &value, sizeof(value)); 48 return le32_to_cpu(value); 49 } 50 51 uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key) 52 { 53 uint64_t value; 54 qfw_cfg_get(fw_cfg, key, &value, sizeof(value)); 55 return le64_to_cpu(value); 56 } 57 58 static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key) 59 { 60 qtest_writew(fw_cfg->qts, fw_cfg->base, key); 61 } 62 63 /* 64 * The caller need check the return value. When the return value is 65 * nonzero, it means that some bytes have been transferred. 66 * 67 * If the fw_cfg file in question is smaller than the allocated & passed-in 68 * buffer, then the buffer has been populated only in part. 69 * 70 * If the fw_cfg file in question is larger than the passed-in 71 * buffer, then the return value explains how much room would have been 72 * necessary in total. And, while the caller's buffer has been fully 73 * populated, it has received only a starting slice of the fw_cfg file. 74 */ 75 size_t qfw_cfg_get_file(QFWCFG *fw_cfg, const char *filename, 76 void *data, size_t buflen) 77 { 78 uint32_t count; 79 uint32_t i; 80 unsigned char *filesbuf = NULL; 81 size_t dsize; 82 FWCfgFile *pdir_entry; 83 size_t filesize = 0; 84 85 qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, &count, sizeof(count)); 86 count = be32_to_cpu(count); 87 dsize = sizeof(uint32_t) + count * sizeof(struct fw_cfg_file); 88 filesbuf = g_malloc(dsize); 89 qfw_cfg_get(fw_cfg, FW_CFG_FILE_DIR, filesbuf, dsize); 90 pdir_entry = (FWCfgFile *)(filesbuf + sizeof(uint32_t)); 91 for (i = 0; i < count; ++i, ++pdir_entry) { 92 if (!strcmp(pdir_entry->name, filename)) { 93 uint32_t len = be32_to_cpu(pdir_entry->size); 94 uint16_t sel = be16_to_cpu(pdir_entry->select); 95 filesize = len; 96 if (len > buflen) { 97 len = buflen; 98 } 99 qfw_cfg_get(fw_cfg, sel, data, len); 100 break; 101 } 102 } 103 g_free(filesbuf); 104 return filesize; 105 } 106 107 static void mm_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len) 108 { 109 uint8_t *ptr = data; 110 int i; 111 112 for (i = 0; i < len; i++) { 113 ptr[i] = qtest_readb(fw_cfg->qts, fw_cfg->base + 2); 114 } 115 } 116 117 QFWCFG *mm_fw_cfg_init(QTestState *qts, uint64_t base) 118 { 119 QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg)); 120 121 fw_cfg->base = base; 122 fw_cfg->qts = qts; 123 fw_cfg->select = mm_fw_cfg_select; 124 fw_cfg->read = mm_fw_cfg_read; 125 126 return fw_cfg; 127 } 128 129 void mm_fw_cfg_uninit(QFWCFG *fw_cfg) 130 { 131 g_free(fw_cfg); 132 } 133 134 static void io_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key) 135 { 136 qtest_outw(fw_cfg->qts, fw_cfg->base, key); 137 } 138 139 static void io_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len) 140 { 141 uint8_t *ptr = data; 142 int i; 143 144 for (i = 0; i < len; i++) { 145 ptr[i] = qtest_inb(fw_cfg->qts, fw_cfg->base + 1); 146 } 147 } 148 149 QFWCFG *io_fw_cfg_init(QTestState *qts, uint16_t base) 150 { 151 QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg)); 152 153 fw_cfg->base = base; 154 fw_cfg->qts = qts; 155 fw_cfg->select = io_fw_cfg_select; 156 fw_cfg->read = io_fw_cfg_read; 157 158 return fw_cfg; 159 } 160 161 void io_fw_cfg_uninit(QFWCFG *fw_cfg) 162 { 163 g_free(fw_cfg); 164 } 165