Home | History | Annotate | Download | only in nvram
      1 /*
      2  * QEMU Firmware configuration device emulation
      3  *
      4  * Copyright (c) 2008 Gleb Natapov
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 #include "cpu.h"
     25 #include "hw/hw.h"
     26 #include "sysemu/sysemu.h"
     27 #include "hw/isa/isa.h"
     28 #include "hw/nvram/fw_cfg.h"
     29 
     30 /* debug firmware config */
     31 //#define DEBUG_FW_CFG
     32 
     33 #ifdef DEBUG_FW_CFG
     34 #define FW_CFG_DPRINTF(fmt, ...)                        \
     35     do { printf("FW_CFG: " fmt , ## __VA_ARGS__); } while (0)
     36 #else
     37 #define FW_CFG_DPRINTF(fmt, ...)
     38 #endif
     39 
     40 #define FW_CFG_SIZE 2
     41 
     42 typedef struct _FWCfgEntry {
     43     uint16_t len;
     44     uint8_t *data;
     45     void *callback_opaque;
     46     FWCfgCallback callback;
     47 } FWCfgEntry;
     48 
     49 struct FWCfgState {
     50     FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
     51     uint16_t cur_entry;
     52     uint16_t cur_offset;
     53 };
     54 
     55 static void fw_cfg_write(FWCfgState *s, uint8_t value)
     56 {
     57     int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
     58     FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
     59 
     60     FW_CFG_DPRINTF("write %d\n", value);
     61 
     62     if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) {
     63         e->data[s->cur_offset++] = value;
     64         if (s->cur_offset == e->len) {
     65             e->callback(e->callback_opaque, e->data);
     66             s->cur_offset = 0;
     67         }
     68     }
     69 }
     70 
     71 static int fw_cfg_select(FWCfgState *s, uint16_t key)
     72 {
     73     int ret;
     74 
     75     s->cur_offset = 0;
     76     if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
     77         s->cur_entry = FW_CFG_INVALID;
     78         ret = 0;
     79     } else {
     80         s->cur_entry = key;
     81         ret = 1;
     82     }
     83 
     84     FW_CFG_DPRINTF("select key %d (%sfound)\n", key, ret ? "" : "not ");
     85 
     86     return ret;
     87 }
     88 
     89 static uint8_t fw_cfg_read(FWCfgState *s)
     90 {
     91     int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
     92     FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
     93     uint8_t ret;
     94 
     95     if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
     96         ret = 0;
     97     else
     98         ret = e->data[s->cur_offset++];
     99 
    100     FW_CFG_DPRINTF("read %d\n", ret);
    101 
    102     return ret;
    103 }
    104 
    105 static uint32_t fw_cfg_io_readb(void *opaque, uint32_t addr)
    106 {
    107     return fw_cfg_read(opaque);
    108 }
    109 
    110 static void fw_cfg_io_writeb(void *opaque, uint32_t addr, uint32_t value)
    111 {
    112     fw_cfg_write(opaque, (uint8_t)value);
    113 }
    114 
    115 static void fw_cfg_io_writew(void *opaque, uint32_t addr, uint32_t value)
    116 {
    117     fw_cfg_select(opaque, (uint16_t)value);
    118 }
    119 
    120 static uint32_t fw_cfg_mem_readb(void *opaque, hwaddr addr)
    121 {
    122     return fw_cfg_read(opaque);
    123 }
    124 
    125 static void fw_cfg_mem_writeb(void *opaque, hwaddr addr,
    126                               uint32_t value)
    127 {
    128     fw_cfg_write(opaque, (uint8_t)value);
    129 }
    130 
    131 static void fw_cfg_mem_writew(void *opaque, hwaddr addr,
    132                               uint32_t value)
    133 {
    134     fw_cfg_select(opaque, (uint16_t)value);
    135 }
    136 
    137 static CPUReadMemoryFunc *fw_cfg_ctl_mem_read[3] = {
    138     NULL,
    139     NULL,
    140     NULL,
    141 };
    142 
    143 static CPUWriteMemoryFunc *fw_cfg_ctl_mem_write[3] = {
    144     NULL,
    145     fw_cfg_mem_writew,
    146     NULL,
    147 };
    148 
    149 static CPUReadMemoryFunc *fw_cfg_data_mem_read[3] = {
    150     fw_cfg_mem_readb,
    151     NULL,
    152     NULL,
    153 };
    154 
    155 static CPUWriteMemoryFunc *fw_cfg_data_mem_write[3] = {
    156     fw_cfg_mem_writeb,
    157     NULL,
    158     NULL,
    159 };
    160 
    161 static void fw_cfg_reset(void *opaque)
    162 {
    163     FWCfgState *s = opaque;
    164 
    165     fw_cfg_select(s, 0);
    166 }
    167 
    168 static void fw_cfg_save(QEMUFile *f, void *opaque)
    169 {
    170     FWCfgState *s = opaque;
    171 
    172     qemu_put_be16s(f, &s->cur_entry);
    173     qemu_put_be16s(f, &s->cur_offset);
    174 }
    175 
    176 static int fw_cfg_load(QEMUFile *f, void *opaque, int version_id)
    177 {
    178     FWCfgState *s = opaque;
    179 
    180     if (version_id > 1)
    181         return -EINVAL;
    182 
    183     qemu_get_be16s(f, &s->cur_entry);
    184     qemu_get_be16s(f, &s->cur_offset);
    185 
    186     return 0;
    187 }
    188 
    189 int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint16_t len)
    190 {
    191     FWCfgState *s = opaque;
    192     int arch = !!(key & FW_CFG_ARCH_LOCAL);
    193 
    194     key &= FW_CFG_ENTRY_MASK;
    195 
    196     if (key >= FW_CFG_MAX_ENTRY)
    197         return 0;
    198 
    199     s->entries[arch][key].data = data;
    200     s->entries[arch][key].len = len;
    201 
    202     return 1;
    203 }
    204 
    205 int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value)
    206 {
    207     uint16_t *copy;
    208 
    209     copy = g_malloc(sizeof(value));
    210     *copy = cpu_to_le16(value);
    211     return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
    212 }
    213 
    214 int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value)
    215 {
    216     uint32_t *copy;
    217 
    218     copy = g_malloc(sizeof(value));
    219     *copy = cpu_to_le32(value);
    220     return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
    221 }
    222 
    223 int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value)
    224 {
    225     uint64_t *copy;
    226 
    227     copy = g_malloc(sizeof(value));
    228     *copy = cpu_to_le64(value);
    229     return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
    230 }
    231 
    232 int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback,
    233                         void *callback_opaque, uint8_t *data, size_t len)
    234 {
    235     FWCfgState *s = opaque;
    236     int arch = !!(key & FW_CFG_ARCH_LOCAL);
    237 
    238     if (!(key & FW_CFG_WRITE_CHANNEL))
    239         return 0;
    240 
    241     key &= FW_CFG_ENTRY_MASK;
    242 
    243     if (key >= FW_CFG_MAX_ENTRY || len > 65535)
    244         return 0;
    245 
    246     s->entries[arch][key].data = data;
    247     s->entries[arch][key].len = len;
    248     s->entries[arch][key].callback_opaque = callback_opaque;
    249     s->entries[arch][key].callback = callback;
    250 
    251     return 1;
    252 }
    253 
    254 void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
    255 		hwaddr ctl_addr, hwaddr data_addr)
    256 {
    257     FWCfgState *s;
    258     int io_ctl_memory, io_data_memory;
    259 
    260     s = g_malloc0(sizeof(FWCfgState));
    261 
    262     if (ctl_port) {
    263         register_ioport_write(ctl_port, 2, 2, fw_cfg_io_writew, s);
    264     }
    265     if (data_port) {
    266         register_ioport_read(data_port, 1, 1, fw_cfg_io_readb, s);
    267         register_ioport_write(data_port, 1, 1, fw_cfg_io_writeb, s);
    268     }
    269     if (ctl_addr) {
    270         io_ctl_memory = cpu_register_io_memory(fw_cfg_ctl_mem_read,
    271                                            fw_cfg_ctl_mem_write, s);
    272         cpu_register_physical_memory(ctl_addr, FW_CFG_SIZE, io_ctl_memory);
    273     }
    274     if (data_addr) {
    275         io_data_memory = cpu_register_io_memory(fw_cfg_data_mem_read,
    276                                            fw_cfg_data_mem_write, s);
    277         cpu_register_physical_memory(data_addr, FW_CFG_SIZE, io_data_memory);
    278     }
    279     fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (uint8_t *)"QEMU", 4);
    280     fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
    281     fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
    282     fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
    283 
    284     register_savevm(NULL, "fw_cfg", -1, 1, fw_cfg_save, fw_cfg_load, s);
    285     qemu_register_reset(fw_cfg_reset, 0, s);
    286     fw_cfg_reset(s);
    287 
    288     return s;
    289 }
    290