symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/fw_cfg.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 "hw.h"
       
    25 #include "sysemu.h"
       
    26 #include "isa.h"
       
    27 #include "fw_cfg.h"
       
    28 
       
    29 /* debug firmware config */
       
    30 //#define DEBUG_FW_CFG
       
    31 
       
    32 #ifdef DEBUG_FW_CFG
       
    33 #define FW_CFG_DPRINTF(fmt, args...)                     \
       
    34     do { printf("FW_CFG: " fmt , ##args); } while (0)
       
    35 #else
       
    36 #define FW_CFG_DPRINTF(fmt, args...)
       
    37 #endif
       
    38 
       
    39 #define FW_CFG_SIZE 2
       
    40 
       
    41 typedef struct _FWCfgEntry {
       
    42     uint16_t len;
       
    43     uint8_t *data;
       
    44     void *callback_opaque;
       
    45     FWCfgCallback callback;
       
    46 } FWCfgEntry;
       
    47 
       
    48 typedef struct _FWCfgState {
       
    49     FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
       
    50     uint16_t cur_entry;
       
    51     uint16_t cur_offset;
       
    52 } FWCfgState;
       
    53 
       
    54 static void fw_cfg_write(FWCfgState *s, uint8_t value)
       
    55 {
       
    56     int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
       
    57     FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
       
    58 
       
    59     FW_CFG_DPRINTF("write %d\n", value);
       
    60 
       
    61     if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) {
       
    62         e->data[s->cur_offset++] = value;
       
    63         if (s->cur_offset == e->len) {
       
    64             e->callback(e->callback_opaque, e->data);
       
    65             s->cur_offset = 0;
       
    66         }
       
    67     }
       
    68 }
       
    69 
       
    70 static int fw_cfg_select(FWCfgState *s, uint16_t key)
       
    71 {
       
    72     int ret;
       
    73 
       
    74     s->cur_offset = 0;
       
    75     if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
       
    76         s->cur_entry = FW_CFG_INVALID;
       
    77         ret = 0;
       
    78     } else {
       
    79         s->cur_entry = key;
       
    80         ret = 1;
       
    81     }
       
    82 
       
    83     FW_CFG_DPRINTF("select key %d (%sfound)\n", key, ret ? "" : "not ");
       
    84 
       
    85     return ret;
       
    86 }
       
    87 
       
    88 static uint8_t fw_cfg_read(FWCfgState *s)
       
    89 {
       
    90     int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
       
    91     FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
       
    92     uint8_t ret;
       
    93 
       
    94     if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
       
    95         ret = 0;
       
    96     else
       
    97         ret = e->data[s->cur_offset++];
       
    98 
       
    99     FW_CFG_DPRINTF("read %d\n", ret);
       
   100 
       
   101     return ret;
       
   102 }
       
   103 
       
   104 static uint32_t fw_cfg_io_readb(void *opaque, uint32_t addr)
       
   105 {
       
   106     return fw_cfg_read(opaque);
       
   107 }
       
   108 
       
   109 static void fw_cfg_io_writeb(void *opaque, uint32_t addr, uint32_t value)
       
   110 {
       
   111     return fw_cfg_write(opaque, (uint8_t)value);
       
   112 }
       
   113 
       
   114 static void fw_cfg_io_writew(void *opaque, uint32_t addr, uint32_t value)
       
   115 {
       
   116     fw_cfg_select(opaque, (uint16_t)value);
       
   117 }
       
   118 
       
   119 static uint32_t fw_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
       
   120 {
       
   121     return fw_cfg_read(opaque);
       
   122 }
       
   123 
       
   124 static void fw_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
       
   125                               uint32_t value)
       
   126 {
       
   127     return fw_cfg_write(opaque, (uint8_t)value);
       
   128 }
       
   129 
       
   130 static void fw_cfg_mem_writew(void *opaque, target_phys_addr_t addr,
       
   131                               uint32_t value)
       
   132 {
       
   133     fw_cfg_select(opaque, (uint16_t)value);
       
   134 }
       
   135 
       
   136 static CPUReadMemoryFunc *fw_cfg_ctl_mem_read[3] = {
       
   137     NULL,
       
   138     NULL,
       
   139     NULL,
       
   140 };
       
   141 
       
   142 static CPUWriteMemoryFunc *fw_cfg_ctl_mem_write[3] = {
       
   143     NULL,
       
   144     fw_cfg_mem_writew,
       
   145     NULL,
       
   146 };
       
   147 
       
   148 static CPUReadMemoryFunc *fw_cfg_data_mem_read[3] = {
       
   149     fw_cfg_mem_readb,
       
   150     NULL,
       
   151     NULL,
       
   152 };
       
   153 
       
   154 static CPUWriteMemoryFunc *fw_cfg_data_mem_write[3] = {
       
   155     fw_cfg_mem_writeb,
       
   156     NULL,
       
   157     NULL,
       
   158 };
       
   159 
       
   160 static void fw_cfg_reset(void *opaque)
       
   161 {
       
   162     FWCfgState *s = opaque;
       
   163 
       
   164     fw_cfg_select(s, 0);
       
   165 }
       
   166 
       
   167 static void fw_cfg_save(QEMUFile *f, void *opaque)
       
   168 {
       
   169     FWCfgState *s = opaque;
       
   170 
       
   171     qemu_put_be16s(f, &s->cur_entry);
       
   172     qemu_put_be16s(f, &s->cur_offset);
       
   173 }
       
   174 
       
   175 static int fw_cfg_load(QEMUFile *f, void *opaque, int version_id)
       
   176 {
       
   177     FWCfgState *s = opaque;
       
   178 
       
   179     if (version_id > 1)
       
   180         return -EINVAL;
       
   181 
       
   182     qemu_get_be16s(f, &s->cur_entry);
       
   183     qemu_get_be16s(f, &s->cur_offset);
       
   184 
       
   185     return 0;
       
   186 }
       
   187 
       
   188 int fw_cfg_add_bytes(void *opaque, uint16_t key, uint8_t *data, uint16_t len)
       
   189 {
       
   190     FWCfgState *s = opaque;
       
   191     int arch = !!(key & FW_CFG_ARCH_LOCAL);
       
   192 
       
   193     key &= FW_CFG_ENTRY_MASK;
       
   194 
       
   195     if (key >= FW_CFG_MAX_ENTRY)
       
   196         return 0;
       
   197 
       
   198     s->entries[arch][key].data = data;
       
   199     s->entries[arch][key].len = len;
       
   200 
       
   201     return 1;
       
   202 }
       
   203 
       
   204 int fw_cfg_add_i16(void *opaque, uint16_t key, uint16_t value)
       
   205 {
       
   206     uint16_t *copy;
       
   207 
       
   208     copy = qemu_malloc(sizeof(value));
       
   209     if (!copy)
       
   210         return 0;
       
   211     *copy = cpu_to_le16(value);
       
   212     return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
       
   213 }
       
   214 
       
   215 int fw_cfg_add_i32(void *opaque, uint16_t key, uint32_t value)
       
   216 {
       
   217     uint32_t *copy;
       
   218 
       
   219     copy = qemu_malloc(sizeof(value));
       
   220     if (!copy)
       
   221         return 0;
       
   222     *copy = cpu_to_le32(value);
       
   223     return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
       
   224 }
       
   225 
       
   226 int fw_cfg_add_i64(void *opaque, uint16_t key, uint64_t value)
       
   227 {
       
   228     uint64_t *copy;
       
   229 
       
   230     copy = qemu_malloc(sizeof(value));
       
   231     if (!copy)
       
   232         return 0;
       
   233     *copy = cpu_to_le64(value);
       
   234     return fw_cfg_add_bytes(opaque, key, (uint8_t *)copy, sizeof(value));
       
   235 }
       
   236 
       
   237 int fw_cfg_add_callback(void *opaque, uint16_t key, FWCfgCallback callback,
       
   238                         void *callback_opaque, uint8_t *data, size_t len)
       
   239 {
       
   240     FWCfgState *s = opaque;
       
   241     int arch = !!(key & FW_CFG_ARCH_LOCAL);
       
   242 
       
   243     if (!(key & FW_CFG_WRITE_CHANNEL))
       
   244         return 0;
       
   245 
       
   246     key &= FW_CFG_ENTRY_MASK;
       
   247 
       
   248     if (key >= FW_CFG_MAX_ENTRY || len > 65535)
       
   249         return 0;
       
   250 
       
   251     s->entries[arch][key].data = data;
       
   252     s->entries[arch][key].len = len;
       
   253     s->entries[arch][key].callback_opaque = callback_opaque;
       
   254     s->entries[arch][key].callback = callback;
       
   255 
       
   256     return 1;
       
   257 }
       
   258 
       
   259 void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
       
   260 		target_phys_addr_t ctl_addr, target_phys_addr_t data_addr)
       
   261 {
       
   262     FWCfgState *s;
       
   263     int io_ctl_memory, io_data_memory;
       
   264 
       
   265     s = qemu_mallocz(sizeof(FWCfgState));
       
   266     if (!s)
       
   267         return NULL;
       
   268 
       
   269     if (ctl_port) {
       
   270         register_ioport_write(ctl_port, 2, 2, fw_cfg_io_writew, s);
       
   271     }
       
   272     if (data_port) {
       
   273         register_ioport_read(data_port, 1, 1, fw_cfg_io_readb, s);
       
   274         register_ioport_write(data_port, 1, 1, fw_cfg_io_writeb, s);
       
   275     }
       
   276     if (ctl_addr) {
       
   277         io_ctl_memory = cpu_register_io_memory(0, fw_cfg_ctl_mem_read,
       
   278                                            fw_cfg_ctl_mem_write, s);
       
   279         cpu_register_physical_memory(ctl_addr, FW_CFG_SIZE, io_ctl_memory);
       
   280     }
       
   281     if (data_addr) {
       
   282         io_data_memory = cpu_register_io_memory(0, fw_cfg_data_mem_read,
       
   283                                            fw_cfg_data_mem_write, s);
       
   284         cpu_register_physical_memory(data_addr, FW_CFG_SIZE, io_data_memory);
       
   285     }
       
   286     fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (uint8_t *)"QEMU", 4);
       
   287     fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
       
   288     fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)nographic);
       
   289     fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
       
   290 
       
   291     register_savevm("fw_cfg", -1, 1, fw_cfg_save, fw_cfg_load, s);
       
   292     qemu_register_reset(fw_cfg_reset, s);
       
   293     fw_cfg_reset(s);
       
   294 
       
   295     return s;
       
   296 }