qemu/hw/mac_nvram.c
<<
>>
Prefs
   1/*
   2 * PowerMac NVRAM emulation
   3 *
   4 * Copyright (c) 2005-2007 Fabrice Bellard
   5 * Copyright (c) 2007 Jocelyn Mayer
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25#include "hw.h"
  26#include "firmware_abi.h"
  27#include "sysemu.h"
  28#include "ppc_mac.h"
  29
  30/* debug NVR */
  31//#define DEBUG_NVR
  32
  33#ifdef DEBUG_NVR
  34#define NVR_DPRINTF(fmt, ...)                                   \
  35    do { printf("NVR: " fmt , ## __VA_ARGS__); } while (0)
  36#else
  37#define NVR_DPRINTF(fmt, ...)
  38#endif
  39
  40struct MacIONVRAMState {
  41    uint32_t size;
  42    MemoryRegion mem;
  43    unsigned int it_shift;
  44    uint8_t *data;
  45};
  46
  47#define DEF_SYSTEM_SIZE 0xc10
  48
  49/* Direct access to NVRAM */
  50uint32_t macio_nvram_read (void *opaque, uint32_t addr)
  51{
  52    MacIONVRAMState *s = opaque;
  53    uint32_t ret;
  54
  55    if (addr < s->size)
  56        ret = s->data[addr];
  57    else
  58        ret = -1;
  59    NVR_DPRINTF("read addr %04x val %x\n", addr, ret);
  60
  61    return ret;
  62}
  63
  64void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val)
  65{
  66    MacIONVRAMState *s = opaque;
  67
  68    NVR_DPRINTF("write addr %04x val %x\n", addr, val);
  69    if (addr < s->size)
  70        s->data[addr] = val;
  71}
  72
  73/* macio style NVRAM device */
  74static void macio_nvram_writeb(void *opaque, target_phys_addr_t addr,
  75                               uint64_t value, unsigned size)
  76{
  77    MacIONVRAMState *s = opaque;
  78
  79    addr = (addr >> s->it_shift) & (s->size - 1);
  80    s->data[addr] = value;
  81    NVR_DPRINTF("writeb addr %04x val %x\n", (int)addr, value);
  82}
  83
  84static uint64_t macio_nvram_readb(void *opaque, target_phys_addr_t addr,
  85                                  unsigned size)
  86{
  87    MacIONVRAMState *s = opaque;
  88    uint32_t value;
  89
  90    addr = (addr >> s->it_shift) & (s->size - 1);
  91    value = s->data[addr];
  92    NVR_DPRINTF("readb addr %04x val %x\n", (int)addr, value);
  93
  94    return value;
  95}
  96
  97static const MemoryRegionOps macio_nvram_ops = {
  98    .read = macio_nvram_readb,
  99    .write = macio_nvram_writeb,
 100    .endianness = DEVICE_NATIVE_ENDIAN,
 101};
 102
 103static const VMStateDescription vmstate_macio_nvram = {
 104    .name = "macio_nvram",
 105    .version_id = 1,
 106    .minimum_version_id = 1,
 107    .minimum_version_id_old = 1,
 108    .fields      = (VMStateField[]) {
 109        VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size),
 110        VMSTATE_END_OF_LIST()
 111    }
 112};
 113
 114
 115static void macio_nvram_reset(void *opaque)
 116{
 117}
 118
 119MacIONVRAMState *macio_nvram_init (target_phys_addr_t size,
 120                                   unsigned int it_shift)
 121{
 122    MacIONVRAMState *s;
 123
 124    s = g_malloc0(sizeof(MacIONVRAMState));
 125    s->data = g_malloc0(size);
 126    s->size = size;
 127    s->it_shift = it_shift;
 128
 129    memory_region_init_io(&s->mem, &macio_nvram_ops, s, "macio-nvram",
 130                          size << it_shift);
 131    vmstate_register(NULL, -1, &vmstate_macio_nvram, s);
 132    qemu_register_reset(macio_nvram_reset, s);
 133
 134    return s;
 135}
 136
 137void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar,
 138                           target_phys_addr_t mem_base)
 139{
 140    memory_region_add_subregion(bar, mem_base, &s->mem);
 141}
 142
 143/* Set up a system OpenBIOS NVRAM partition */
 144void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len)
 145{
 146    unsigned int i;
 147    uint32_t start = 0, end;
 148    struct OpenBIOS_nvpart_v1 *part_header;
 149
 150    // OpenBIOS nvram variables
 151    // Variable partition
 152    part_header = (struct OpenBIOS_nvpart_v1 *)nvr->data;
 153    part_header->signature = OPENBIOS_PART_SYSTEM;
 154    pstrcpy(part_header->name, sizeof(part_header->name), "system");
 155
 156    end = start + sizeof(struct OpenBIOS_nvpart_v1);
 157    for (i = 0; i < nb_prom_envs; i++)
 158        end = OpenBIOS_set_var(nvr->data, end, prom_envs[i]);
 159
 160    // End marker
 161    nvr->data[end++] = '\0';
 162
 163    end = start + ((end - start + 15) & ~15);
 164    /* XXX: OpenBIOS is not able to grow up a partition. Leave some space for
 165       new variables. */
 166    if (end < DEF_SYSTEM_SIZE)
 167        end = DEF_SYSTEM_SIZE;
 168    OpenBIOS_finish_partition(part_header, end - start);
 169
 170    // free partition
 171    start = end;
 172    part_header = (struct OpenBIOS_nvpart_v1 *)&nvr->data[start];
 173    part_header->signature = OPENBIOS_PART_FREE;
 174    pstrcpy(part_header->name, sizeof(part_header->name), "free");
 175
 176    end = len;
 177    OpenBIOS_finish_partition(part_header, end - start);
 178}
 179