qemu/hw/block/ecc.c
<<
>>
Prefs
   1/*
   2 * Calculate Error-correcting Codes. Used by NAND Flash controllers
   3 * (not by NAND chips).
   4 *
   5 * Copyright (c) 2006 Openedhand Ltd.
   6 * Written by Andrzej Zaborowski <balrog@zabor.org>
   7 *
   8 * This code is licensed under the GNU GPL v2.
   9 *
  10 * Contributions after 2012-01-13 are licensed under the terms of the
  11 * GNU GPL, version 2 or (at your option) any later version.
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "migration/vmstate.h"
  16#include "hw/block/flash.h"
  17
  18/*
  19 * Pre-calculated 256-way 1 byte column parity.  Table borrowed from Linux.
  20 */
  21static const uint8_t nand_ecc_precalc_table[] = {
  22    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
  23    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
  24    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
  25    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
  26    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
  27    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
  28    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
  29    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
  30    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
  31    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
  32    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
  33    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
  34    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
  35    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
  36    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
  37    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
  38    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
  39    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
  40    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
  41    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
  42    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
  43    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
  44    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
  45    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
  46    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
  47    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
  48    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
  49    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
  50    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
  51    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
  52    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
  53    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
  54};
  55
  56/* Update ECC parity count.  */
  57uint8_t ecc_digest(ECCState *s, uint8_t sample)
  58{
  59    uint8_t idx = nand_ecc_precalc_table[sample];
  60
  61    s->cp ^= idx & 0x3f;
  62    if (idx & 0x40) {
  63        s->lp[0] ^= ~s->count;
  64        s->lp[1] ^= s->count;
  65    }
  66    s->count ++;
  67
  68    return sample;
  69}
  70
  71/* Reinitialise the counters.  */
  72void ecc_reset(ECCState *s)
  73{
  74    s->lp[0] = 0x0000;
  75    s->lp[1] = 0x0000;
  76    s->cp = 0x00;
  77    s->count = 0;
  78}
  79
  80/* Save/restore */
  81VMStateDescription vmstate_ecc_state = {
  82    .name = "ecc-state",
  83    .version_id = 0,
  84    .minimum_version_id = 0,
  85    .fields = (VMStateField[]) {
  86        VMSTATE_UINT8(cp, ECCState),
  87        VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
  88        VMSTATE_UINT16(count, ECCState),
  89        VMSTATE_END_OF_LIST(),
  90    },
  91};
  92