1 | /* |
2 | * CFI parallel flash with Intel command set emulation |
3 | * |
4 | * Copyright (c) 2006 Thorsten Zitterell |
5 | * Copyright (c) 2005 Jocelyn Mayer |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | /* |
22 | * For now, this code can emulate flashes of 1, 2 or 4 bytes width. |
23 | * Supported commands/modes are: |
24 | * - flash read |
25 | * - flash write |
26 | * - flash ID read |
27 | * - sector erase |
28 | * - CFI queries |
29 | * |
30 | * It does not support timings |
31 | * It does not support flash interleaving |
32 | * It does not implement software data protection as found in many real chips |
33 | * It does not implement erase suspend/resume commands |
34 | * It does not implement multiple sectors erase |
35 | * |
36 | * It does not implement much more ... |
37 | */ |
38 | |
39 | #include "qemu/osdep.h" |
40 | #include "hw/block/block.h" |
41 | #include "hw/block/flash.h" |
42 | #include "hw/qdev-properties.h" |
43 | #include "sysemu/block-backend.h" |
44 | #include "qapi/error.h" |
45 | #include "qemu/timer.h" |
46 | #include "qemu/bitops.h" |
47 | #include "qemu/error-report.h" |
48 | #include "qemu/host-utils.h" |
49 | #include "qemu/log.h" |
50 | #include "qemu/module.h" |
51 | #include "qemu/option.h" |
52 | #include "hw/sysbus.h" |
53 | #include "migration/vmstate.h" |
54 | #include "sysemu/blockdev.h" |
55 | #include "sysemu/runstate.h" |
56 | #include "trace.h" |
57 | |
58 | /* #define PFLASH_DEBUG */ |
59 | #ifdef PFLASH_DEBUG |
60 | #define DPRINTF(fmt, ...) \ |
61 | do { \ |
62 | fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__); \ |
63 | } while (0) |
64 | #else |
65 | #define DPRINTF(fmt, ...) do { } while (0) |
66 | #endif |
67 | |
68 | #define PFLASH_BE 0 |
69 | #define PFLASH_SECURE 1 |
70 | |
71 | struct PFlashCFI01 { |
72 | /*< private >*/ |
73 | SysBusDevice parent_obj; |
74 | /*< public >*/ |
75 | |
76 | BlockBackend *blk; |
77 | uint32_t nb_blocs; |
78 | uint64_t sector_len; |
79 | uint8_t bank_width; |
80 | uint8_t device_width; /* If 0, device width not specified. */ |
81 | uint8_t max_device_width; /* max device width in bytes */ |
82 | uint32_t features; |
83 | uint8_t wcycle; /* if 0, the flash is read normally */ |
84 | int ro; |
85 | uint8_t cmd; |
86 | uint8_t status; |
87 | uint16_t ident0; |
88 | uint16_t ident1; |
89 | uint16_t ident2; |
90 | uint16_t ident3; |
91 | uint8_t cfi_table[0x52]; |
92 | uint64_t counter; |
93 | unsigned int writeblock_size; |
94 | QEMUTimer *timer; |
95 | MemoryRegion mem; |
96 | char *name; |
97 | void *storage; |
98 | VMChangeStateEntry *vmstate; |
99 | bool old_multiple_chip_handling; |
100 | }; |
101 | |
102 | static int pflash_post_load(void *opaque, int version_id); |
103 | |
104 | static const VMStateDescription vmstate_pflash = { |
105 | .name = "pflash_cfi01" , |
106 | .version_id = 1, |
107 | .minimum_version_id = 1, |
108 | .post_load = pflash_post_load, |
109 | .fields = (VMStateField[]) { |
110 | VMSTATE_UINT8(wcycle, PFlashCFI01), |
111 | VMSTATE_UINT8(cmd, PFlashCFI01), |
112 | VMSTATE_UINT8(status, PFlashCFI01), |
113 | VMSTATE_UINT64(counter, PFlashCFI01), |
114 | VMSTATE_END_OF_LIST() |
115 | } |
116 | }; |
117 | |
118 | static void pflash_timer (void *opaque) |
119 | { |
120 | PFlashCFI01 *pfl = opaque; |
121 | |
122 | trace_pflash_timer_expired(pfl->cmd); |
123 | /* Reset flash */ |
124 | pfl->status ^= 0x80; |
125 | memory_region_rom_device_set_romd(&pfl->mem, true); |
126 | pfl->wcycle = 0; |
127 | pfl->cmd = 0; |
128 | } |
129 | |
130 | /* Perform a CFI query based on the bank width of the flash. |
131 | * If this code is called we know we have a device_width set for |
132 | * this flash. |
133 | */ |
134 | static uint32_t pflash_cfi_query(PFlashCFI01 *pfl, hwaddr offset) |
135 | { |
136 | int i; |
137 | uint32_t resp = 0; |
138 | hwaddr boff; |
139 | |
140 | /* Adjust incoming offset to match expected device-width |
141 | * addressing. CFI query addresses are always specified in terms of |
142 | * the maximum supported width of the device. This means that x8 |
143 | * devices and x8/x16 devices in x8 mode behave differently. For |
144 | * devices that are not used at their max width, we will be |
145 | * provided with addresses that use higher address bits than |
146 | * expected (based on the max width), so we will shift them lower |
147 | * so that they will match the addresses used when |
148 | * device_width==max_device_width. |
149 | */ |
150 | boff = offset >> (ctz32(pfl->bank_width) + |
151 | ctz32(pfl->max_device_width) - ctz32(pfl->device_width)); |
152 | |
153 | if (boff >= sizeof(pfl->cfi_table)) { |
154 | return 0; |
155 | } |
156 | /* Now we will construct the CFI response generated by a single |
157 | * device, then replicate that for all devices that make up the |
158 | * bus. For wide parts used in x8 mode, CFI query responses |
159 | * are different than native byte-wide parts. |
160 | */ |
161 | resp = pfl->cfi_table[boff]; |
162 | if (pfl->device_width != pfl->max_device_width) { |
163 | /* The only case currently supported is x8 mode for a |
164 | * wider part. |
165 | */ |
166 | if (pfl->device_width != 1 || pfl->bank_width > 4) { |
167 | DPRINTF("%s: Unsupported device configuration: " |
168 | "device_width=%d, max_device_width=%d\n" , |
169 | __func__, pfl->device_width, |
170 | pfl->max_device_width); |
171 | return 0; |
172 | } |
173 | /* CFI query data is repeated, rather than zero padded for |
174 | * wide devices used in x8 mode. |
175 | */ |
176 | for (i = 1; i < pfl->max_device_width; i++) { |
177 | resp = deposit32(resp, 8 * i, 8, pfl->cfi_table[boff]); |
178 | } |
179 | } |
180 | /* Replicate responses for each device in bank. */ |
181 | if (pfl->device_width < pfl->bank_width) { |
182 | for (i = pfl->device_width; |
183 | i < pfl->bank_width; i += pfl->device_width) { |
184 | resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp); |
185 | } |
186 | } |
187 | |
188 | return resp; |
189 | } |
190 | |
191 | |
192 | |
193 | /* Perform a device id query based on the bank width of the flash. */ |
194 | static uint32_t pflash_devid_query(PFlashCFI01 *pfl, hwaddr offset) |
195 | { |
196 | int i; |
197 | uint32_t resp; |
198 | hwaddr boff; |
199 | |
200 | /* Adjust incoming offset to match expected device-width |
201 | * addressing. Device ID read addresses are always specified in |
202 | * terms of the maximum supported width of the device. This means |
203 | * that x8 devices and x8/x16 devices in x8 mode behave |
204 | * differently. For devices that are not used at their max width, |
205 | * we will be provided with addresses that use higher address bits |
206 | * than expected (based on the max width), so we will shift them |
207 | * lower so that they will match the addresses used when |
208 | * device_width==max_device_width. |
209 | */ |
210 | boff = offset >> (ctz32(pfl->bank_width) + |
211 | ctz32(pfl->max_device_width) - ctz32(pfl->device_width)); |
212 | |
213 | /* Mask off upper bits which may be used in to query block |
214 | * or sector lock status at other addresses. |
215 | * Offsets 2/3 are block lock status, is not emulated. |
216 | */ |
217 | switch (boff & 0xFF) { |
218 | case 0: |
219 | resp = pfl->ident0; |
220 | trace_pflash_manufacturer_id(resp); |
221 | break; |
222 | case 1: |
223 | resp = pfl->ident1; |
224 | trace_pflash_device_id(resp); |
225 | break; |
226 | default: |
227 | trace_pflash_device_info(offset); |
228 | return 0; |
229 | break; |
230 | } |
231 | /* Replicate responses for each device in bank. */ |
232 | if (pfl->device_width < pfl->bank_width) { |
233 | for (i = pfl->device_width; |
234 | i < pfl->bank_width; i += pfl->device_width) { |
235 | resp = deposit32(resp, 8 * i, 8 * pfl->device_width, resp); |
236 | } |
237 | } |
238 | |
239 | return resp; |
240 | } |
241 | |
242 | static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset, |
243 | int width, int be) |
244 | { |
245 | uint8_t *p; |
246 | uint32_t ret; |
247 | |
248 | p = pfl->storage; |
249 | switch (width) { |
250 | case 1: |
251 | ret = p[offset]; |
252 | break; |
253 | case 2: |
254 | if (be) { |
255 | ret = p[offset] << 8; |
256 | ret |= p[offset + 1]; |
257 | } else { |
258 | ret = p[offset]; |
259 | ret |= p[offset + 1] << 8; |
260 | } |
261 | break; |
262 | case 4: |
263 | if (be) { |
264 | ret = p[offset] << 24; |
265 | ret |= p[offset + 1] << 16; |
266 | ret |= p[offset + 2] << 8; |
267 | ret |= p[offset + 3]; |
268 | } else { |
269 | ret = p[offset]; |
270 | ret |= p[offset + 1] << 8; |
271 | ret |= p[offset + 2] << 16; |
272 | ret |= p[offset + 3] << 24; |
273 | } |
274 | break; |
275 | default: |
276 | DPRINTF("BUG in %s\n" , __func__); |
277 | abort(); |
278 | } |
279 | trace_pflash_data_read(offset, width << 1, ret); |
280 | return ret; |
281 | } |
282 | |
283 | static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, |
284 | int width, int be) |
285 | { |
286 | hwaddr boff; |
287 | uint32_t ret; |
288 | |
289 | ret = -1; |
290 | switch (pfl->cmd) { |
291 | default: |
292 | /* This should never happen : reset state & treat it as a read */ |
293 | DPRINTF("%s: unknown command state: %x\n" , __func__, pfl->cmd); |
294 | pfl->wcycle = 0; |
295 | pfl->cmd = 0; |
296 | /* fall through to read code */ |
297 | case 0x00: |
298 | /* Flash area read */ |
299 | ret = pflash_data_read(pfl, offset, width, be); |
300 | break; |
301 | case 0x10: /* Single byte program */ |
302 | case 0x20: /* Block erase */ |
303 | case 0x28: /* Block erase */ |
304 | case 0x40: /* single byte program */ |
305 | case 0x50: /* Clear status register */ |
306 | case 0x60: /* Block /un)lock */ |
307 | case 0x70: /* Status Register */ |
308 | case 0xe8: /* Write block */ |
309 | /* Status register read. Return status from each device in |
310 | * bank. |
311 | */ |
312 | ret = pfl->status; |
313 | if (pfl->device_width && width > pfl->device_width) { |
314 | int shift = pfl->device_width * 8; |
315 | while (shift + pfl->device_width * 8 <= width * 8) { |
316 | ret |= pfl->status << shift; |
317 | shift += pfl->device_width * 8; |
318 | } |
319 | } else if (!pfl->device_width && width > 2) { |
320 | /* Handle 32 bit flash cases where device width is not |
321 | * set. (Existing behavior before device width added.) |
322 | */ |
323 | ret |= pfl->status << 16; |
324 | } |
325 | DPRINTF("%s: status %x\n" , __func__, ret); |
326 | break; |
327 | case 0x90: |
328 | if (!pfl->device_width) { |
329 | /* Preserve old behavior if device width not specified */ |
330 | boff = offset & 0xFF; |
331 | if (pfl->bank_width == 2) { |
332 | boff = boff >> 1; |
333 | } else if (pfl->bank_width == 4) { |
334 | boff = boff >> 2; |
335 | } |
336 | |
337 | switch (boff) { |
338 | case 0: |
339 | ret = pfl->ident0 << 8 | pfl->ident1; |
340 | trace_pflash_manufacturer_id(ret); |
341 | break; |
342 | case 1: |
343 | ret = pfl->ident2 << 8 | pfl->ident3; |
344 | trace_pflash_device_id(ret); |
345 | break; |
346 | default: |
347 | trace_pflash_device_info(boff); |
348 | ret = 0; |
349 | break; |
350 | } |
351 | } else { |
352 | /* If we have a read larger than the bank_width, combine multiple |
353 | * manufacturer/device ID queries into a single response. |
354 | */ |
355 | int i; |
356 | for (i = 0; i < width; i += pfl->bank_width) { |
357 | ret = deposit32(ret, i * 8, pfl->bank_width * 8, |
358 | pflash_devid_query(pfl, |
359 | offset + i * pfl->bank_width)); |
360 | } |
361 | } |
362 | break; |
363 | case 0x98: /* Query mode */ |
364 | if (!pfl->device_width) { |
365 | /* Preserve old behavior if device width not specified */ |
366 | boff = offset & 0xFF; |
367 | if (pfl->bank_width == 2) { |
368 | boff = boff >> 1; |
369 | } else if (pfl->bank_width == 4) { |
370 | boff = boff >> 2; |
371 | } |
372 | |
373 | if (boff < sizeof(pfl->cfi_table)) { |
374 | ret = pfl->cfi_table[boff]; |
375 | } else { |
376 | ret = 0; |
377 | } |
378 | } else { |
379 | /* If we have a read larger than the bank_width, combine multiple |
380 | * CFI queries into a single response. |
381 | */ |
382 | int i; |
383 | for (i = 0; i < width; i += pfl->bank_width) { |
384 | ret = deposit32(ret, i * 8, pfl->bank_width * 8, |
385 | pflash_cfi_query(pfl, |
386 | offset + i * pfl->bank_width)); |
387 | } |
388 | } |
389 | |
390 | break; |
391 | } |
392 | trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle); |
393 | |
394 | return ret; |
395 | } |
396 | |
397 | /* update flash content on disk */ |
398 | static void pflash_update(PFlashCFI01 *pfl, int offset, |
399 | int size) |
400 | { |
401 | int offset_end; |
402 | if (pfl->blk) { |
403 | offset_end = offset + size; |
404 | /* widen to sector boundaries */ |
405 | offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); |
406 | offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE); |
407 | blk_pwrite(pfl->blk, offset, pfl->storage + offset, |
408 | offset_end - offset, 0); |
409 | } |
410 | } |
411 | |
412 | static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset, |
413 | uint32_t value, int width, int be) |
414 | { |
415 | uint8_t *p = pfl->storage; |
416 | |
417 | trace_pflash_data_write(offset, width << 1, value, pfl->counter); |
418 | switch (width) { |
419 | case 1: |
420 | p[offset] = value; |
421 | break; |
422 | case 2: |
423 | if (be) { |
424 | p[offset] = value >> 8; |
425 | p[offset + 1] = value; |
426 | } else { |
427 | p[offset] = value; |
428 | p[offset + 1] = value >> 8; |
429 | } |
430 | break; |
431 | case 4: |
432 | if (be) { |
433 | p[offset] = value >> 24; |
434 | p[offset + 1] = value >> 16; |
435 | p[offset + 2] = value >> 8; |
436 | p[offset + 3] = value; |
437 | } else { |
438 | p[offset] = value; |
439 | p[offset + 1] = value >> 8; |
440 | p[offset + 2] = value >> 16; |
441 | p[offset + 3] = value >> 24; |
442 | } |
443 | break; |
444 | } |
445 | |
446 | } |
447 | |
448 | static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, |
449 | uint32_t value, int width, int be) |
450 | { |
451 | uint8_t *p; |
452 | uint8_t cmd; |
453 | |
454 | cmd = value; |
455 | |
456 | trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle); |
457 | if (!pfl->wcycle) { |
458 | /* Set the device in I/O access mode */ |
459 | memory_region_rom_device_set_romd(&pfl->mem, false); |
460 | } |
461 | |
462 | switch (pfl->wcycle) { |
463 | case 0: |
464 | /* read mode */ |
465 | switch (cmd) { |
466 | case 0x00: /* ??? */ |
467 | goto reset_flash; |
468 | case 0x10: /* Single Byte Program */ |
469 | case 0x40: /* Single Byte Program */ |
470 | DPRINTF("%s: Single Byte Program\n" , __func__); |
471 | break; |
472 | case 0x20: /* Block erase */ |
473 | p = pfl->storage; |
474 | offset &= ~(pfl->sector_len - 1); |
475 | |
476 | DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n" , |
477 | __func__, offset, (unsigned)pfl->sector_len); |
478 | |
479 | if (!pfl->ro) { |
480 | memset(p + offset, 0xff, pfl->sector_len); |
481 | pflash_update(pfl, offset, pfl->sector_len); |
482 | } else { |
483 | pfl->status |= 0x20; /* Block erase error */ |
484 | } |
485 | pfl->status |= 0x80; /* Ready! */ |
486 | break; |
487 | case 0x50: /* Clear status bits */ |
488 | DPRINTF("%s: Clear status bits\n" , __func__); |
489 | pfl->status = 0x0; |
490 | goto reset_flash; |
491 | case 0x60: /* Block (un)lock */ |
492 | DPRINTF("%s: Block unlock\n" , __func__); |
493 | break; |
494 | case 0x70: /* Status Register */ |
495 | DPRINTF("%s: Read status register\n" , __func__); |
496 | pfl->cmd = cmd; |
497 | return; |
498 | case 0x90: /* Read Device ID */ |
499 | DPRINTF("%s: Read Device information\n" , __func__); |
500 | pfl->cmd = cmd; |
501 | return; |
502 | case 0x98: /* CFI query */ |
503 | DPRINTF("%s: CFI query\n" , __func__); |
504 | break; |
505 | case 0xe8: /* Write to buffer */ |
506 | DPRINTF("%s: Write to buffer\n" , __func__); |
507 | /* FIXME should save @offset, @width for case 1+ */ |
508 | qemu_log_mask(LOG_UNIMP, |
509 | "%s: Write to buffer emulation is flawed\n" , |
510 | __func__); |
511 | pfl->status |= 0x80; /* Ready! */ |
512 | break; |
513 | case 0xf0: /* Probe for AMD flash */ |
514 | DPRINTF("%s: Probe for AMD flash\n" , __func__); |
515 | goto reset_flash; |
516 | case 0xff: /* Read array mode */ |
517 | DPRINTF("%s: Read array mode\n" , __func__); |
518 | goto reset_flash; |
519 | default: |
520 | goto error_flash; |
521 | } |
522 | pfl->wcycle++; |
523 | pfl->cmd = cmd; |
524 | break; |
525 | case 1: |
526 | switch (pfl->cmd) { |
527 | case 0x10: /* Single Byte Program */ |
528 | case 0x40: /* Single Byte Program */ |
529 | DPRINTF("%s: Single Byte Program\n" , __func__); |
530 | if (!pfl->ro) { |
531 | pflash_data_write(pfl, offset, value, width, be); |
532 | pflash_update(pfl, offset, width); |
533 | } else { |
534 | pfl->status |= 0x10; /* Programming error */ |
535 | } |
536 | pfl->status |= 0x80; /* Ready! */ |
537 | pfl->wcycle = 0; |
538 | break; |
539 | case 0x20: /* Block erase */ |
540 | case 0x28: |
541 | if (cmd == 0xd0) { /* confirm */ |
542 | pfl->wcycle = 0; |
543 | pfl->status |= 0x80; |
544 | } else if (cmd == 0xff) { /* read array mode */ |
545 | goto reset_flash; |
546 | } else |
547 | goto error_flash; |
548 | |
549 | break; |
550 | case 0xe8: |
551 | /* Mask writeblock size based on device width, or bank width if |
552 | * device width not specified. |
553 | */ |
554 | /* FIXME check @offset, @width */ |
555 | if (pfl->device_width) { |
556 | value = extract32(value, 0, pfl->device_width * 8); |
557 | } else { |
558 | value = extract32(value, 0, pfl->bank_width * 8); |
559 | } |
560 | DPRINTF("%s: block write of %x bytes\n" , __func__, value); |
561 | pfl->counter = value; |
562 | pfl->wcycle++; |
563 | break; |
564 | case 0x60: |
565 | if (cmd == 0xd0) { |
566 | pfl->wcycle = 0; |
567 | pfl->status |= 0x80; |
568 | } else if (cmd == 0x01) { |
569 | pfl->wcycle = 0; |
570 | pfl->status |= 0x80; |
571 | } else if (cmd == 0xff) { |
572 | goto reset_flash; |
573 | } else { |
574 | DPRINTF("%s: Unknown (un)locking command\n" , __func__); |
575 | goto reset_flash; |
576 | } |
577 | break; |
578 | case 0x98: |
579 | if (cmd == 0xff) { |
580 | goto reset_flash; |
581 | } else { |
582 | DPRINTF("%s: leaving query mode\n" , __func__); |
583 | } |
584 | break; |
585 | default: |
586 | goto error_flash; |
587 | } |
588 | break; |
589 | case 2: |
590 | switch (pfl->cmd) { |
591 | case 0xe8: /* Block write */ |
592 | /* FIXME check @offset, @width */ |
593 | if (!pfl->ro) { |
594 | /* |
595 | * FIXME writing straight to memory is *wrong*. We |
596 | * should write to a buffer, and flush it to memory |
597 | * only on confirm command (see below). |
598 | */ |
599 | pflash_data_write(pfl, offset, value, width, be); |
600 | } else { |
601 | pfl->status |= 0x10; /* Programming error */ |
602 | } |
603 | |
604 | pfl->status |= 0x80; |
605 | |
606 | if (!pfl->counter) { |
607 | hwaddr mask = pfl->writeblock_size - 1; |
608 | mask = ~mask; |
609 | |
610 | DPRINTF("%s: block write finished\n" , __func__); |
611 | pfl->wcycle++; |
612 | if (!pfl->ro) { |
613 | /* Flush the entire write buffer onto backing storage. */ |
614 | /* FIXME premature! */ |
615 | pflash_update(pfl, offset & mask, pfl->writeblock_size); |
616 | } else { |
617 | pfl->status |= 0x10; /* Programming error */ |
618 | } |
619 | } |
620 | |
621 | pfl->counter--; |
622 | break; |
623 | default: |
624 | goto error_flash; |
625 | } |
626 | break; |
627 | case 3: /* Confirm mode */ |
628 | switch (pfl->cmd) { |
629 | case 0xe8: /* Block write */ |
630 | if (cmd == 0xd0) { |
631 | /* FIXME this is where we should write out the buffer */ |
632 | pfl->wcycle = 0; |
633 | pfl->status |= 0x80; |
634 | } else { |
635 | qemu_log_mask(LOG_UNIMP, |
636 | "%s: Aborting write to buffer not implemented," |
637 | " the data is already written to storage!\n" |
638 | "Flash device reset into READ mode.\n" , |
639 | __func__); |
640 | goto reset_flash; |
641 | } |
642 | break; |
643 | default: |
644 | goto error_flash; |
645 | } |
646 | break; |
647 | default: |
648 | /* Should never happen */ |
649 | DPRINTF("%s: invalid write state\n" , __func__); |
650 | goto reset_flash; |
651 | } |
652 | return; |
653 | |
654 | error_flash: |
655 | qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence " |
656 | "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" |
657 | "\n" , __func__, offset, pfl->wcycle, pfl->cmd, value); |
658 | |
659 | reset_flash: |
660 | trace_pflash_reset(); |
661 | memory_region_rom_device_set_romd(&pfl->mem, true); |
662 | pfl->wcycle = 0; |
663 | pfl->cmd = 0; |
664 | } |
665 | |
666 | |
667 | static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_t *value, |
668 | unsigned len, MemTxAttrs attrs) |
669 | { |
670 | PFlashCFI01 *pfl = opaque; |
671 | bool be = !!(pfl->features & (1 << PFLASH_BE)); |
672 | |
673 | if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) { |
674 | *value = pflash_data_read(opaque, addr, len, be); |
675 | } else { |
676 | *value = pflash_read(opaque, addr, len, be); |
677 | } |
678 | return MEMTX_OK; |
679 | } |
680 | |
681 | static MemTxResult pflash_mem_write_with_attrs(void *opaque, hwaddr addr, uint64_t value, |
682 | unsigned len, MemTxAttrs attrs) |
683 | { |
684 | PFlashCFI01 *pfl = opaque; |
685 | bool be = !!(pfl->features & (1 << PFLASH_BE)); |
686 | |
687 | if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) { |
688 | return MEMTX_ERROR; |
689 | } else { |
690 | pflash_write(opaque, addr, value, len, be); |
691 | return MEMTX_OK; |
692 | } |
693 | } |
694 | |
695 | static const MemoryRegionOps pflash_cfi01_ops = { |
696 | .read_with_attrs = pflash_mem_read_with_attrs, |
697 | .write_with_attrs = pflash_mem_write_with_attrs, |
698 | .endianness = DEVICE_NATIVE_ENDIAN, |
699 | }; |
700 | |
701 | static void pflash_cfi01_realize(DeviceState *dev, Error **errp) |
702 | { |
703 | PFlashCFI01 *pfl = PFLASH_CFI01(dev); |
704 | uint64_t total_len; |
705 | int ret; |
706 | uint64_t blocks_per_device, sector_len_per_device, device_len; |
707 | int num_devices; |
708 | Error *local_err = NULL; |
709 | |
710 | if (pfl->sector_len == 0) { |
711 | error_setg(errp, "attribute \"sector-length\" not specified or zero." ); |
712 | return; |
713 | } |
714 | if (pfl->nb_blocs == 0) { |
715 | error_setg(errp, "attribute \"num-blocks\" not specified or zero." ); |
716 | return; |
717 | } |
718 | if (pfl->name == NULL) { |
719 | error_setg(errp, "attribute \"name\" not specified." ); |
720 | return; |
721 | } |
722 | |
723 | total_len = pfl->sector_len * pfl->nb_blocs; |
724 | |
725 | /* These are only used to expose the parameters of each device |
726 | * in the cfi_table[]. |
727 | */ |
728 | num_devices = pfl->device_width ? (pfl->bank_width / pfl->device_width) : 1; |
729 | if (pfl->old_multiple_chip_handling) { |
730 | blocks_per_device = pfl->nb_blocs / num_devices; |
731 | sector_len_per_device = pfl->sector_len; |
732 | } else { |
733 | blocks_per_device = pfl->nb_blocs; |
734 | sector_len_per_device = pfl->sector_len / num_devices; |
735 | } |
736 | device_len = sector_len_per_device * blocks_per_device; |
737 | |
738 | memory_region_init_rom_device( |
739 | &pfl->mem, OBJECT(dev), |
740 | &pflash_cfi01_ops, |
741 | pfl, |
742 | pfl->name, total_len, &local_err); |
743 | if (local_err) { |
744 | error_propagate(errp, local_err); |
745 | return; |
746 | } |
747 | |
748 | pfl->storage = memory_region_get_ram_ptr(&pfl->mem); |
749 | sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); |
750 | |
751 | if (pfl->blk) { |
752 | uint64_t perm; |
753 | pfl->ro = blk_is_read_only(pfl->blk); |
754 | perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE); |
755 | ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp); |
756 | if (ret < 0) { |
757 | return; |
758 | } |
759 | } else { |
760 | pfl->ro = 0; |
761 | } |
762 | |
763 | if (pfl->blk) { |
764 | if (!blk_check_size_and_read_all(pfl->blk, pfl->storage, total_len, |
765 | errp)) { |
766 | vmstate_unregister_ram(&pfl->mem, DEVICE(pfl)); |
767 | return; |
768 | } |
769 | } |
770 | |
771 | /* Default to devices being used at their maximum device width. This was |
772 | * assumed before the device_width support was added. |
773 | */ |
774 | if (!pfl->max_device_width) { |
775 | pfl->max_device_width = pfl->device_width; |
776 | } |
777 | |
778 | pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); |
779 | pfl->wcycle = 0; |
780 | pfl->cmd = 0; |
781 | pfl->status = 0x80; /* WSM ready */ |
782 | /* Hardcoded CFI table */ |
783 | /* Standard "QRY" string */ |
784 | pfl->cfi_table[0x10] = 'Q'; |
785 | pfl->cfi_table[0x11] = 'R'; |
786 | pfl->cfi_table[0x12] = 'Y'; |
787 | /* Command set (Intel) */ |
788 | pfl->cfi_table[0x13] = 0x01; |
789 | pfl->cfi_table[0x14] = 0x00; |
790 | /* Primary extended table address (none) */ |
791 | pfl->cfi_table[0x15] = 0x31; |
792 | pfl->cfi_table[0x16] = 0x00; |
793 | /* Alternate command set (none) */ |
794 | pfl->cfi_table[0x17] = 0x00; |
795 | pfl->cfi_table[0x18] = 0x00; |
796 | /* Alternate extended table (none) */ |
797 | pfl->cfi_table[0x19] = 0x00; |
798 | pfl->cfi_table[0x1A] = 0x00; |
799 | /* Vcc min */ |
800 | pfl->cfi_table[0x1B] = 0x45; |
801 | /* Vcc max */ |
802 | pfl->cfi_table[0x1C] = 0x55; |
803 | /* Vpp min (no Vpp pin) */ |
804 | pfl->cfi_table[0x1D] = 0x00; |
805 | /* Vpp max (no Vpp pin) */ |
806 | pfl->cfi_table[0x1E] = 0x00; |
807 | /* Reserved */ |
808 | pfl->cfi_table[0x1F] = 0x07; |
809 | /* Timeout for min size buffer write */ |
810 | pfl->cfi_table[0x20] = 0x07; |
811 | /* Typical timeout for block erase */ |
812 | pfl->cfi_table[0x21] = 0x0a; |
813 | /* Typical timeout for full chip erase (4096 ms) */ |
814 | pfl->cfi_table[0x22] = 0x00; |
815 | /* Reserved */ |
816 | pfl->cfi_table[0x23] = 0x04; |
817 | /* Max timeout for buffer write */ |
818 | pfl->cfi_table[0x24] = 0x04; |
819 | /* Max timeout for block erase */ |
820 | pfl->cfi_table[0x25] = 0x04; |
821 | /* Max timeout for chip erase */ |
822 | pfl->cfi_table[0x26] = 0x00; |
823 | /* Device size */ |
824 | pfl->cfi_table[0x27] = ctz32(device_len); /* + 1; */ |
825 | /* Flash device interface (8 & 16 bits) */ |
826 | pfl->cfi_table[0x28] = 0x02; |
827 | pfl->cfi_table[0x29] = 0x00; |
828 | /* Max number of bytes in multi-bytes write */ |
829 | if (pfl->bank_width == 1) { |
830 | pfl->cfi_table[0x2A] = 0x08; |
831 | } else { |
832 | pfl->cfi_table[0x2A] = 0x0B; |
833 | } |
834 | pfl->writeblock_size = 1 << pfl->cfi_table[0x2A]; |
835 | if (!pfl->old_multiple_chip_handling && num_devices > 1) { |
836 | pfl->writeblock_size *= num_devices; |
837 | } |
838 | |
839 | pfl->cfi_table[0x2B] = 0x00; |
840 | /* Number of erase block regions (uniform) */ |
841 | pfl->cfi_table[0x2C] = 0x01; |
842 | /* Erase block region 1 */ |
843 | pfl->cfi_table[0x2D] = blocks_per_device - 1; |
844 | pfl->cfi_table[0x2E] = (blocks_per_device - 1) >> 8; |
845 | pfl->cfi_table[0x2F] = sector_len_per_device >> 8; |
846 | pfl->cfi_table[0x30] = sector_len_per_device >> 16; |
847 | |
848 | /* Extended */ |
849 | pfl->cfi_table[0x31] = 'P'; |
850 | pfl->cfi_table[0x32] = 'R'; |
851 | pfl->cfi_table[0x33] = 'I'; |
852 | |
853 | pfl->cfi_table[0x34] = '1'; |
854 | pfl->cfi_table[0x35] = '0'; |
855 | |
856 | pfl->cfi_table[0x36] = 0x00; |
857 | pfl->cfi_table[0x37] = 0x00; |
858 | pfl->cfi_table[0x38] = 0x00; |
859 | pfl->cfi_table[0x39] = 0x00; |
860 | |
861 | pfl->cfi_table[0x3a] = 0x00; |
862 | |
863 | pfl->cfi_table[0x3b] = 0x00; |
864 | pfl->cfi_table[0x3c] = 0x00; |
865 | |
866 | pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */ |
867 | } |
868 | |
869 | static void pflash_cfi01_system_reset(DeviceState *dev) |
870 | { |
871 | PFlashCFI01 *pfl = PFLASH_CFI01(dev); |
872 | |
873 | /* |
874 | * The command 0x00 is not assigned by the CFI open standard, |
875 | * but QEMU historically uses it for the READ_ARRAY command (0xff). |
876 | */ |
877 | pfl->cmd = 0x00; |
878 | pfl->wcycle = 0; |
879 | memory_region_rom_device_set_romd(&pfl->mem, true); |
880 | /* |
881 | * The WSM ready timer occurs at most 150ns after system reset. |
882 | * This model deliberately ignores this delay. |
883 | */ |
884 | pfl->status = 0x80; |
885 | } |
886 | |
887 | static Property pflash_cfi01_properties[] = { |
888 | DEFINE_PROP_DRIVE("drive" , PFlashCFI01, blk), |
889 | /* num-blocks is the number of blocks actually visible to the guest, |
890 | * ie the total size of the device divided by the sector length. |
891 | * If we're emulating flash devices wired in parallel the actual |
892 | * number of blocks per indvidual device will differ. |
893 | */ |
894 | DEFINE_PROP_UINT32("num-blocks" , PFlashCFI01, nb_blocs, 0), |
895 | DEFINE_PROP_UINT64("sector-length" , PFlashCFI01, sector_len, 0), |
896 | /* width here is the overall width of this QEMU device in bytes. |
897 | * The QEMU device may be emulating a number of flash devices |
898 | * wired up in parallel; the width of each individual flash |
899 | * device should be specified via device-width. If the individual |
900 | * devices have a maximum width which is greater than the width |
901 | * they are being used for, this maximum width should be set via |
902 | * max-device-width (which otherwise defaults to device-width). |
903 | * So for instance a 32-bit wide QEMU flash device made from four |
904 | * 16-bit flash devices used in 8-bit wide mode would be configured |
905 | * with width = 4, device-width = 1, max-device-width = 2. |
906 | * |
907 | * If device-width is not specified we default to backwards |
908 | * compatible behaviour which is a bad emulation of two |
909 | * 16 bit devices making up a 32 bit wide QEMU device. This |
910 | * is deprecated for new uses of this device. |
911 | */ |
912 | DEFINE_PROP_UINT8("width" , PFlashCFI01, bank_width, 0), |
913 | DEFINE_PROP_UINT8("device-width" , PFlashCFI01, device_width, 0), |
914 | DEFINE_PROP_UINT8("max-device-width" , PFlashCFI01, max_device_width, 0), |
915 | DEFINE_PROP_BIT("big-endian" , PFlashCFI01, features, PFLASH_BE, 0), |
916 | DEFINE_PROP_BIT("secure" , PFlashCFI01, features, PFLASH_SECURE, 0), |
917 | DEFINE_PROP_UINT16("id0" , PFlashCFI01, ident0, 0), |
918 | DEFINE_PROP_UINT16("id1" , PFlashCFI01, ident1, 0), |
919 | DEFINE_PROP_UINT16("id2" , PFlashCFI01, ident2, 0), |
920 | DEFINE_PROP_UINT16("id3" , PFlashCFI01, ident3, 0), |
921 | DEFINE_PROP_STRING("name" , PFlashCFI01, name), |
922 | DEFINE_PROP_BOOL("old-multiple-chip-handling" , PFlashCFI01, |
923 | old_multiple_chip_handling, false), |
924 | DEFINE_PROP_END_OF_LIST(), |
925 | }; |
926 | |
927 | static void pflash_cfi01_class_init(ObjectClass *klass, void *data) |
928 | { |
929 | DeviceClass *dc = DEVICE_CLASS(klass); |
930 | |
931 | dc->reset = pflash_cfi01_system_reset; |
932 | dc->realize = pflash_cfi01_realize; |
933 | dc->props = pflash_cfi01_properties; |
934 | dc->vmsd = &vmstate_pflash; |
935 | set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); |
936 | } |
937 | |
938 | |
939 | static const TypeInfo pflash_cfi01_info = { |
940 | .name = TYPE_PFLASH_CFI01, |
941 | .parent = TYPE_SYS_BUS_DEVICE, |
942 | .instance_size = sizeof(PFlashCFI01), |
943 | .class_init = pflash_cfi01_class_init, |
944 | }; |
945 | |
946 | static void pflash_cfi01_register_types(void) |
947 | { |
948 | type_register_static(&pflash_cfi01_info); |
949 | } |
950 | |
951 | type_init(pflash_cfi01_register_types) |
952 | |
953 | PFlashCFI01 *pflash_cfi01_register(hwaddr base, |
954 | const char *name, |
955 | hwaddr size, |
956 | BlockBackend *blk, |
957 | uint32_t sector_len, |
958 | int bank_width, |
959 | uint16_t id0, uint16_t id1, |
960 | uint16_t id2, uint16_t id3, |
961 | int be) |
962 | { |
963 | DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); |
964 | |
965 | if (blk) { |
966 | qdev_prop_set_drive(dev, "drive" , blk, &error_abort); |
967 | } |
968 | assert(size % sector_len == 0); |
969 | qdev_prop_set_uint32(dev, "num-blocks" , size / sector_len); |
970 | qdev_prop_set_uint64(dev, "sector-length" , sector_len); |
971 | qdev_prop_set_uint8(dev, "width" , bank_width); |
972 | qdev_prop_set_bit(dev, "big-endian" , !!be); |
973 | qdev_prop_set_uint16(dev, "id0" , id0); |
974 | qdev_prop_set_uint16(dev, "id1" , id1); |
975 | qdev_prop_set_uint16(dev, "id2" , id2); |
976 | qdev_prop_set_uint16(dev, "id3" , id3); |
977 | qdev_prop_set_string(dev, "name" , name); |
978 | qdev_init_nofail(dev); |
979 | |
980 | sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); |
981 | return PFLASH_CFI01(dev); |
982 | } |
983 | |
984 | BlockBackend *pflash_cfi01_get_blk(PFlashCFI01 *fl) |
985 | { |
986 | return fl->blk; |
987 | } |
988 | |
989 | MemoryRegion *pflash_cfi01_get_memory(PFlashCFI01 *fl) |
990 | { |
991 | return &fl->mem; |
992 | } |
993 | |
994 | /* |
995 | * Handle -drive if=pflash for machines that use properties. |
996 | * If @dinfo is null, do nothing. |
997 | * Else if @fl's property "drive" is already set, fatal error. |
998 | * Else set it to the BlockBackend with @dinfo. |
999 | */ |
1000 | void pflash_cfi01_legacy_drive(PFlashCFI01 *fl, DriveInfo *dinfo) |
1001 | { |
1002 | Location loc; |
1003 | |
1004 | if (!dinfo) { |
1005 | return; |
1006 | } |
1007 | |
1008 | loc_push_none(&loc); |
1009 | qemu_opts_loc_restore(dinfo->opts); |
1010 | if (fl->blk) { |
1011 | error_report("clashes with -machine" ); |
1012 | exit(1); |
1013 | } |
1014 | qdev_prop_set_drive(DEVICE(fl), "drive" , |
1015 | blk_by_legacy_dinfo(dinfo), &error_fatal); |
1016 | loc_pop(&loc); |
1017 | } |
1018 | |
1019 | static void postload_update_cb(void *opaque, int running, RunState state) |
1020 | { |
1021 | PFlashCFI01 *pfl = opaque; |
1022 | |
1023 | /* This is called after bdrv_invalidate_cache_all. */ |
1024 | qemu_del_vm_change_state_handler(pfl->vmstate); |
1025 | pfl->vmstate = NULL; |
1026 | |
1027 | DPRINTF("%s: updating bdrv for %s\n" , __func__, pfl->name); |
1028 | pflash_update(pfl, 0, pfl->sector_len * pfl->nb_blocs); |
1029 | } |
1030 | |
1031 | static int pflash_post_load(void *opaque, int version_id) |
1032 | { |
1033 | PFlashCFI01 *pfl = opaque; |
1034 | |
1035 | if (!pfl->ro) { |
1036 | pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, |
1037 | pfl); |
1038 | } |
1039 | return 0; |
1040 | } |
1041 | |