xref: /openbmc/qemu/hw/misc/aspeed_sbc.c (revision c302bf8549805b91d65b93fd9f1248807ec17283)
1 /*
2  * ASPEED Secure Boot Controller
3  *
4  * Copyright (C) 2021-2022 IBM Corp.
5  *
6  * Joel Stanley <joel@jms.id.au>
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include "qemu/osdep.h"
12 #include "qemu/log.h"
13 #include "qemu/error-report.h"
14 #include "hw/qdev-properties.h"
15 #include "hw/misc/aspeed_sbc.h"
16 #include "qapi/error.h"
17 #include "migration/vmstate.h"
18 #include "trace.h"
19 
20 #define R_PROT          (0x000 / 4)
21 #define R_CMD           (0x004 / 4)
22 #define R_ADDR          (0x010 / 4)
23 #define R_STATUS        (0x014 / 4)
24 #define R_CAMP1         (0x020 / 4)
25 #define R_CAMP2         (0x024 / 4)
26 #define R_QSR           (0x040 / 4)
27 
28 /* R_STATUS */
29 #define ABR_EN                  BIT(14) /* Mirrors SCU510[11] */
30 #define ABR_IMAGE_SOURCE        BIT(13)
31 #define SPI_ABR_IMAGE_SOURCE    BIT(12)
32 #define SB_CRYPTO_KEY_EXP_DONE  BIT(11)
33 #define SB_CRYPTO_BUSY          BIT(10)
34 #define OTP_WP_EN               BIT(9)
35 #define OTP_ADDR_WP_EN          BIT(8)
36 #define LOW_SEC_KEY_EN          BIT(7)
37 #define SECURE_BOOT_EN          BIT(6)
38 #define UART_BOOT_EN            BIT(5)
39 /* bit 4 reserved*/
40 #define OTP_CHARGE_PUMP_READY   BIT(3)
41 #define OTP_IDLE                BIT(2)
42 #define OTP_MEM_IDLE            BIT(1)
43 #define OTP_COMPARE_STATUS      BIT(0)
44 
45 /* QSR */
46 #define QSR_RSA_MASK           (0x3 << 12)
47 #define QSR_HASH_MASK          (0x3 << 10)
48 
49 #define OTP_MEMORY_SIZE 0x4000
50 /* OTP command */
51 #define SBC_OTP_CMD_READ 0x23b1e361
52 #define SBC_OTP_CMD_WRITE 0x23b1e362
53 #define SBC_OTP_CMD_PROG 0x23b1e364
54 
55 #define OTP_DATA_DWORD_COUNT        (0x800)
56 #define OTP_TOTAL_DWORD_COUNT       (0x1000)
57 
58 /* Voltage mode */
59 #define MODE_REGISTER               (0x1000)
60 #define MODE_REGISTER_A             (0x3000)
61 #define MODE_REGISTER_B             (0x5000)
62 
aspeed_sbc_read(void * opaque,hwaddr addr,unsigned int size)63 static uint64_t aspeed_sbc_read(void *opaque, hwaddr addr, unsigned int size)
64 {
65     AspeedSBCState *s = ASPEED_SBC(opaque);
66 
67     addr >>= 2;
68 
69     if (addr >= ASPEED_SBC_NR_REGS) {
70         qemu_log_mask(LOG_GUEST_ERROR,
71                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
72                       __func__, addr << 2);
73         return 0;
74     }
75 
76     return s->regs[addr];
77 }
78 
aspeed_sbc_otp_read(AspeedSBCState * s,uint32_t otp_addr)79 static bool aspeed_sbc_otp_read(AspeedSBCState *s,
80                                    uint32_t otp_addr)
81 {
82     MemTxResult ret;
83     AspeedOTPState *otp = &s->otp;
84     uint32_t value, otp_offset;
85     bool is_data = false;
86 
87     if (otp_addr < OTP_DATA_DWORD_COUNT) {
88         is_data = true;
89     } else if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
90         qemu_log_mask(LOG_GUEST_ERROR,
91                       "Invalid OTP addr 0x%x\n",
92                       otp_addr);
93         return false;
94     }
95 
96     otp_offset = otp_addr << 2;
97     ret = address_space_read(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
98                              &value, sizeof(value));
99     if (ret != MEMTX_OK) {
100         qemu_log_mask(LOG_GUEST_ERROR,
101                       "Failed to read OTP memory, addr = %x\n",
102                       otp_addr);
103         return false;
104     }
105     s->regs[R_CAMP1] = value;
106     trace_aspeed_sbc_otp_read(otp_addr, value);
107 
108     if (is_data) {
109         ret = address_space_read(&otp->as, otp_offset + 4,
110                                  MEMTXATTRS_UNSPECIFIED,
111                                  &value, sizeof(value));
112         if (ret != MEMTX_OK) {
113             qemu_log_mask(LOG_GUEST_ERROR,
114                           "Failed to read OTP memory, addr = %x\n",
115                           otp_addr);
116             return false;
117         }
118         s->regs[R_CAMP2] = value;
119         trace_aspeed_sbc_otp_read(otp_addr + 1, value);
120     }
121 
122     return true;
123 }
124 
mode_handler(uint32_t otp_addr)125 static bool mode_handler(uint32_t otp_addr)
126 {
127     switch (otp_addr) {
128     case MODE_REGISTER:
129     case MODE_REGISTER_A:
130     case MODE_REGISTER_B:
131         /* HW behavior, do nothing here */
132         return true;
133     default:
134         qemu_log_mask(LOG_GUEST_ERROR,
135                       "Unsupported address 0x%x\n",
136                       otp_addr);
137         return false;
138     }
139 }
140 
aspeed_sbc_otp_write(AspeedSBCState * s,uint32_t otp_addr)141 static bool aspeed_sbc_otp_write(AspeedSBCState *s,
142                                     uint32_t otp_addr)
143 {
144     if (otp_addr == 0) {
145         trace_aspeed_sbc_ignore_cmd(otp_addr);
146         return true;
147     } else {
148         if (mode_handler(otp_addr) == false) {
149             return false;
150         }
151     }
152 
153     return true;
154 }
155 
aspeed_sbc_otp_prog(AspeedSBCState * s,uint32_t otp_addr)156 static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
157                                    uint32_t otp_addr)
158 {
159     MemTxResult ret;
160     AspeedOTPState *otp = &s->otp;
161     uint32_t value = s->regs[R_CAMP1];
162 
163     ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
164                         &value, sizeof(value));
165     if (ret != MEMTX_OK) {
166         qemu_log_mask(LOG_GUEST_ERROR,
167                       "Failed to write OTP memory, addr = %x\n",
168                       otp_addr);
169         return false;
170     }
171 
172     trace_aspeed_sbc_otp_prog(otp_addr, value);
173 
174     return true;
175 }
176 
aspeed_sbc_handle_command(void * opaque,uint32_t cmd)177 static void aspeed_sbc_handle_command(void *opaque, uint32_t cmd)
178 {
179     AspeedSBCState *s = ASPEED_SBC(opaque);
180     AspeedSBCClass *sc = ASPEED_SBC_GET_CLASS(opaque);
181     bool ret = false;
182     uint32_t otp_addr;
183 
184     if (!sc->has_otp) {
185         qemu_log_mask(LOG_GUEST_ERROR,
186                       "%s: OTP memory is not supported\n",
187                       __func__);
188         return;
189     }
190 
191     s->regs[R_STATUS] &= ~(OTP_MEM_IDLE | OTP_IDLE);
192     otp_addr = s->regs[R_ADDR];
193 
194     switch (cmd) {
195     case SBC_OTP_CMD_READ:
196         ret = aspeed_sbc_otp_read(s, otp_addr);
197         break;
198     case SBC_OTP_CMD_WRITE:
199         ret = aspeed_sbc_otp_write(s, otp_addr);
200         break;
201     case SBC_OTP_CMD_PROG:
202         ret = aspeed_sbc_otp_prog(s, otp_addr);
203         break;
204     default:
205         qemu_log_mask(LOG_GUEST_ERROR,
206                       "%s: Unknown command 0x%x\n",
207                       __func__, cmd);
208         break;
209     }
210 
211     trace_aspeed_sbc_handle_cmd(cmd, otp_addr, ret);
212     s->regs[R_STATUS] |= (OTP_MEM_IDLE | OTP_IDLE);
213 }
214 
aspeed_sbc_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)215 static void aspeed_sbc_write(void *opaque, hwaddr addr, uint64_t data,
216                               unsigned int size)
217 {
218     AspeedSBCState *s = ASPEED_SBC(opaque);
219 
220     addr >>= 2;
221 
222     if (addr >= ASPEED_SBC_NR_REGS) {
223         qemu_log_mask(LOG_GUEST_ERROR,
224                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
225                       __func__, addr << 2);
226         return;
227     }
228 
229     switch (addr) {
230     case R_STATUS:
231     case R_QSR:
232         qemu_log_mask(LOG_GUEST_ERROR,
233                       "%s: write to read only register 0x%" HWADDR_PRIx "\n",
234                       __func__, addr << 2);
235         return;
236     case R_CMD:
237         aspeed_sbc_handle_command(opaque, data);
238         return;
239     default:
240         break;
241     }
242 
243     s->regs[addr] = data;
244 }
245 
246 static const MemoryRegionOps aspeed_sbc_ops = {
247     .read = aspeed_sbc_read,
248     .write = aspeed_sbc_write,
249     .endianness = DEVICE_LITTLE_ENDIAN,
250     .valid = {
251         .min_access_size = 1,
252         .max_access_size = 4,
253     },
254 };
255 
aspeed_sbc_reset(DeviceState * dev)256 static void aspeed_sbc_reset(DeviceState *dev)
257 {
258     struct AspeedSBCState *s = ASPEED_SBC(dev);
259 
260     memset(s->regs, 0, sizeof(s->regs));
261 
262     /* Set secure boot enabled with RSA4096_SHA256 and enable eMMC ABR */
263     s->regs[R_STATUS] = OTP_IDLE | OTP_MEM_IDLE;
264 
265     if (s->emmc_abr) {
266         s->regs[R_STATUS] &= ABR_EN;
267     }
268 
269     if (s->signing_settings) {
270         s->regs[R_STATUS] &= SECURE_BOOT_EN;
271     }
272 
273     s->regs[R_QSR] = s->signing_settings;
274 }
275 
aspeed_sbc_instance_init(Object * obj)276 static void aspeed_sbc_instance_init(Object *obj)
277 {
278     AspeedSBCClass *sc = ASPEED_SBC_GET_CLASS(obj);
279     AspeedSBCState *s = ASPEED_SBC(obj);
280 
281     if (sc->has_otp) {
282         object_initialize_child(OBJECT(s), "otp", &s->otp,
283                                 TYPE_ASPEED_OTP);
284     }
285 }
286 
aspeed_sbc_realize(DeviceState * dev,Error ** errp)287 static void aspeed_sbc_realize(DeviceState *dev, Error **errp)
288 {
289     AspeedSBCState *s = ASPEED_SBC(dev);
290     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
291     AspeedSBCClass *sc = ASPEED_SBC_GET_CLASS(dev);
292 
293     if (sc->has_otp) {
294         object_property_set_int(OBJECT(&s->otp), "size",
295                                 OTP_MEMORY_SIZE, &error_abort);
296         if (!qdev_realize(DEVICE(&s->otp), NULL, errp)) {
297             return;
298         }
299     }
300 
301     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sbc_ops, s,
302             TYPE_ASPEED_SBC, 0x1000);
303 
304     sysbus_init_mmio(sbd, &s->iomem);
305 }
306 
307 static const VMStateDescription vmstate_aspeed_sbc = {
308     .name = TYPE_ASPEED_SBC,
309     .version_id = 1,
310     .minimum_version_id = 1,
311     .fields = (const VMStateField[]) {
312         VMSTATE_UINT32_ARRAY(regs, AspeedSBCState, ASPEED_SBC_NR_REGS),
313         VMSTATE_END_OF_LIST(),
314     }
315 };
316 
317 static const Property aspeed_sbc_properties[] = {
318     DEFINE_PROP_BOOL("emmc-abr", AspeedSBCState, emmc_abr, 0),
319     DEFINE_PROP_UINT32("signing-settings", AspeedSBCState, signing_settings, 0),
320 };
321 
aspeed_sbc_class_init(ObjectClass * klass,const void * data)322 static void aspeed_sbc_class_init(ObjectClass *klass, const void *data)
323 {
324     DeviceClass *dc = DEVICE_CLASS(klass);
325 
326     dc->realize = aspeed_sbc_realize;
327     device_class_set_legacy_reset(dc, aspeed_sbc_reset);
328     dc->vmsd = &vmstate_aspeed_sbc;
329     device_class_set_props(dc, aspeed_sbc_properties);
330 }
331 
332 static const TypeInfo aspeed_sbc_info = {
333     .name = TYPE_ASPEED_SBC,
334     .parent = TYPE_SYS_BUS_DEVICE,
335     .instance_size = sizeof(AspeedSBCState),
336     .instance_init = aspeed_sbc_instance_init,
337     .class_init = aspeed_sbc_class_init,
338     .class_size = sizeof(AspeedSBCClass)
339 };
340 
aspeed_ast2600_sbc_class_init(ObjectClass * klass,const void * data)341 static void aspeed_ast2600_sbc_class_init(ObjectClass *klass, const void *data)
342 {
343     DeviceClass *dc = DEVICE_CLASS(klass);
344     AspeedSBCClass *sc = ASPEED_SBC_CLASS(klass);
345 
346     dc->desc = "AST2600 Secure Boot Controller";
347     sc->has_otp = true;
348 }
349 
350 static const TypeInfo aspeed_ast2600_sbc_info = {
351     .name = TYPE_ASPEED_AST2600_SBC,
352     .parent = TYPE_ASPEED_SBC,
353     .class_init = aspeed_ast2600_sbc_class_init,
354 };
355 
aspeed_ast10x0_sbc_class_init(ObjectClass * klass,const void * data)356 static void aspeed_ast10x0_sbc_class_init(ObjectClass *klass, const void *data)
357 {
358     DeviceClass *dc = DEVICE_CLASS(klass);
359     AspeedSBCClass *sc = ASPEED_SBC_CLASS(klass);
360 
361     dc->desc = "AST10X0 Secure Boot Controller";
362     sc->has_otp = true;
363 }
364 
365 static const TypeInfo aspeed_ast10x0_sbc_info = {
366     .name = TYPE_ASPEED_AST10X0_SBC,
367     .parent = TYPE_ASPEED_SBC,
368     .class_init = aspeed_ast10x0_sbc_class_init,
369 };
370 
aspeed_sbc_register_types(void)371 static void aspeed_sbc_register_types(void)
372 {
373     type_register_static(&aspeed_ast2600_sbc_info);
374     type_register_static(&aspeed_ast10x0_sbc_info);
375     type_register_static(&aspeed_sbc_info);
376 }
377 
378 type_init(aspeed_sbc_register_types);
379