]>
Commit | Line | Data |
---|---|---|
234c69c5 AL |
1 | /* |
2 | * libqos fw_cfg support | |
3 | * | |
4 | * Copyright IBM, Corp. 2012-2013 | |
7a100165 | 5 | * Copyright (C) 2013 Red Hat Inc. |
234c69c5 AL |
6 | * |
7 | * Authors: | |
8 | * Anthony Liguori <aliguori@us.ibm.com> | |
7a100165 | 9 | * Markus Armbruster <armbru@redhat.com> |
234c69c5 AL |
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 | ||
681c28a3 | 15 | #include "qemu/osdep.h" |
a2ce7dbd | 16 | #include "fw_cfg.h" |
7a100165 | 17 | #include "libqtest.h" |
1a63e059 | 18 | #include "qemu/bswap.h" |
c99f5f1d | 19 | #include "hw/nvram/fw_cfg.h" |
234c69c5 AL |
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)); | |
1a63e059 | 41 | return le16_to_cpu(value); |
234c69c5 AL |
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)); | |
1a63e059 | 48 | return le32_to_cpu(value); |
234c69c5 AL |
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)); | |
1a63e059 | 55 | return le64_to_cpu(value); |
234c69c5 AL |
56 | } |
57 | ||
7a100165 MA |
58 | static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key) |
59 | { | |
05e520f1 | 60 | qtest_writew(fw_cfg->qts, fw_cfg->base, key); |
7a100165 MA |
61 | } |
62 | ||
c99f5f1d LQ |
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 | ||
7a100165 MA |
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++) { | |
05e520f1 | 113 | ptr[i] = qtest_readb(fw_cfg->qts, fw_cfg->base + 2); |
7a100165 MA |
114 | } |
115 | } | |
116 | ||
05e520f1 | 117 | QFWCFG *mm_fw_cfg_init(QTestState *qts, uint64_t base) |
7a100165 MA |
118 | { |
119 | QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg)); | |
120 | ||
121 | fw_cfg->base = base; | |
05e520f1 | 122 | fw_cfg->qts = qts; |
7a100165 MA |
123 | fw_cfg->select = mm_fw_cfg_select; |
124 | fw_cfg->read = mm_fw_cfg_read; | |
125 | ||
126 | return fw_cfg; | |
127 | } | |
26491a38 | 128 | |
0729d833 PMD |
129 | void mm_fw_cfg_uninit(QFWCFG *fw_cfg) |
130 | { | |
131 | g_free(fw_cfg); | |
132 | } | |
133 | ||
26491a38 MA |
134 | static void io_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key) |
135 | { | |
05e520f1 | 136 | qtest_outw(fw_cfg->qts, fw_cfg->base, key); |
26491a38 MA |
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++) { | |
05e520f1 | 145 | ptr[i] = qtest_inb(fw_cfg->qts, fw_cfg->base + 1); |
26491a38 MA |
146 | } |
147 | } | |
148 | ||
05e520f1 | 149 | QFWCFG *io_fw_cfg_init(QTestState *qts, uint16_t base) |
26491a38 MA |
150 | { |
151 | QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg)); | |
152 | ||
153 | fw_cfg->base = base; | |
05e520f1 | 154 | fw_cfg->qts = qts; |
26491a38 MA |
155 | fw_cfg->select = io_fw_cfg_select; |
156 | fw_cfg->read = io_fw_cfg_read; | |
157 | ||
158 | return fw_cfg; | |
159 | } | |
0729d833 PMD |
160 | |
161 | void io_fw_cfg_uninit(QFWCFG *fw_cfg) | |
162 | { | |
163 | g_free(fw_cfg); | |
164 | } |