xref: /qemu/hw/nvram/spapr_nvram.c (revision ccd241b5a2223c502441714d413d569565e4a3b4)
1  /*
2   * QEMU sPAPR NVRAM emulation
3   *
4   * Copyright (C) 2012 David Gibson, IBM Corporation.
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  
25  #include "qemu/osdep.h"
26  #include <libfdt.h>
27  
28  #include "sysemu/block-backend.h"
29  #include "sysemu/device_tree.h"
30  #include "hw/sysbus.h"
31  #include "hw/ppc/spapr.h"
32  #include "hw/ppc/spapr_vio.h"
33  
34  typedef struct sPAPRNVRAM {
35      VIOsPAPRDevice sdev;
36      uint32_t size;
37      uint8_t *buf;
38      BlockBackend *blk;
39  } sPAPRNVRAM;
40  
41  #define TYPE_VIO_SPAPR_NVRAM "spapr-nvram"
42  #define VIO_SPAPR_NVRAM(obj) \
43       OBJECT_CHECK(sPAPRNVRAM, (obj), TYPE_VIO_SPAPR_NVRAM)
44  
45  #define MIN_NVRAM_SIZE 8192
46  #define DEFAULT_NVRAM_SIZE 65536
47  #define MAX_NVRAM_SIZE 1048576
48  
49  static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPRMachineState *spapr,
50                               uint32_t token, uint32_t nargs,
51                               target_ulong args,
52                               uint32_t nret, target_ulong rets)
53  {
54      sPAPRNVRAM *nvram = spapr->nvram;
55      hwaddr offset, buffer, len;
56      void *membuf;
57  
58      if ((nargs != 3) || (nret != 2)) {
59          rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
60          return;
61      }
62  
63      if (!nvram) {
64          rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
65          rtas_st(rets, 1, 0);
66          return;
67      }
68  
69      offset = rtas_ld(args, 0);
70      buffer = rtas_ld(args, 1);
71      len = rtas_ld(args, 2);
72  
73      if (((offset + len) < offset)
74          || ((offset + len) > nvram->size)) {
75          rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
76          rtas_st(rets, 1, 0);
77          return;
78      }
79  
80      assert(nvram->buf);
81  
82      membuf = cpu_physical_memory_map(buffer, &len, 1);
83      memcpy(membuf, nvram->buf + offset, len);
84      cpu_physical_memory_unmap(membuf, len, 1, len);
85  
86      rtas_st(rets, 0, RTAS_OUT_SUCCESS);
87      rtas_st(rets, 1, len);
88  }
89  
90  static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
91                               uint32_t token, uint32_t nargs,
92                               target_ulong args,
93                               uint32_t nret, target_ulong rets)
94  {
95      sPAPRNVRAM *nvram = spapr->nvram;
96      hwaddr offset, buffer, len;
97      int alen;
98      void *membuf;
99  
100      if ((nargs != 3) || (nret != 2)) {
101          rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
102          return;
103      }
104  
105      if (!nvram) {
106          rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
107          return;
108      }
109  
110      offset = rtas_ld(args, 0);
111      buffer = rtas_ld(args, 1);
112      len = rtas_ld(args, 2);
113  
114      if (((offset + len) < offset)
115          || ((offset + len) > nvram->size)) {
116          rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
117          return;
118      }
119  
120      membuf = cpu_physical_memory_map(buffer, &len, 0);
121  
122      alen = len;
123      if (nvram->blk) {
124          alen = blk_pwrite(nvram->blk, offset, membuf, len);
125      }
126  
127      assert(nvram->buf);
128      memcpy(nvram->buf + offset, membuf, len);
129  
130      cpu_physical_memory_unmap(membuf, len, 0, len);
131  
132      rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS);
133      rtas_st(rets, 1, (alen < 0) ? 0 : alen);
134  }
135  
136  static void spapr_nvram_realize(VIOsPAPRDevice *dev, Error **errp)
137  {
138      sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
139  
140      if (nvram->blk) {
141          nvram->size = blk_getlength(nvram->blk);
142      } else {
143          nvram->size = DEFAULT_NVRAM_SIZE;
144      }
145  
146      nvram->buf = g_malloc0(nvram->size);
147  
148      if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
149          error_setg(errp, "spapr-nvram must be between %d and %d bytes in size",
150                     MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
151          return;
152      }
153  
154      if (nvram->blk) {
155          int alen = blk_pread(nvram->blk, 0, nvram->buf, nvram->size);
156  
157          if (alen != nvram->size) {
158              error_setg(errp, "can't read spapr-nvram contents");
159              return;
160          }
161      }
162  
163      spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);
164      spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
165  }
166  
167  static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
168  {
169      sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
170  
171      return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
172  }
173  
174  static int spapr_nvram_pre_load(void *opaque)
175  {
176      sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
177  
178      g_free(nvram->buf);
179      nvram->buf = NULL;
180      nvram->size = 0;
181  
182      return 0;
183  }
184  
185  static int spapr_nvram_post_load(void *opaque, int version_id)
186  {
187      sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque);
188  
189      if (nvram->blk) {
190          int alen = blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size);
191  
192          if (alen < 0) {
193              return alen;
194          }
195          if (alen != nvram->size) {
196              return -1;
197          }
198      }
199  
200      return 0;
201  }
202  
203  static const VMStateDescription vmstate_spapr_nvram = {
204      .name = "spapr_nvram",
205      .version_id = 1,
206      .minimum_version_id = 1,
207      .pre_load = spapr_nvram_pre_load,
208      .post_load = spapr_nvram_post_load,
209      .fields = (VMStateField[]) {
210          VMSTATE_UINT32(size, sPAPRNVRAM),
211          VMSTATE_VBUFFER_ALLOC_UINT32(buf, sPAPRNVRAM, 1, NULL, 0, size),
212          VMSTATE_END_OF_LIST()
213      },
214  };
215  
216  static Property spapr_nvram_properties[] = {
217      DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
218      DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, blk),
219      DEFINE_PROP_END_OF_LIST(),
220  };
221  
222  static void spapr_nvram_class_init(ObjectClass *klass, void *data)
223  {
224      DeviceClass *dc = DEVICE_CLASS(klass);
225      VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
226  
227      k->realize = spapr_nvram_realize;
228      k->devnode = spapr_nvram_devnode;
229      k->dt_name = "nvram";
230      k->dt_type = "nvram";
231      k->dt_compatible = "qemu,spapr-nvram";
232      set_bit(DEVICE_CATEGORY_MISC, dc->categories);
233      dc->props = spapr_nvram_properties;
234      dc->vmsd = &vmstate_spapr_nvram;
235  }
236  
237  static const TypeInfo spapr_nvram_type_info = {
238      .name          = TYPE_VIO_SPAPR_NVRAM,
239      .parent        = TYPE_VIO_SPAPR_DEVICE,
240      .instance_size = sizeof(sPAPRNVRAM),
241      .class_init    = spapr_nvram_class_init,
242  };
243  
244  static void spapr_nvram_register_types(void)
245  {
246      type_register_static(&spapr_nvram_type_info);
247  }
248  
249  type_init(spapr_nvram_register_types)
250