Annotation of qemu/roms/SLOF/lib/libnvram/nvram.c, revision 1.1.1.2

1.1       root        1: /******************************************************************************
                      2:  * Copyright (c) 2004, 2008 IBM Corporation
                      3:  * All rights reserved.
                      4:  * This program and the accompanying materials
                      5:  * are made available under the terms of the BSD License
                      6:  * which accompanies this distribution, and is available at
                      7:  * http://www.opensource.org/licenses/bsd-license.php
                      8:  *
                      9:  * Contributors:
                     10:  *     IBM Corporation - initial implementation
                     11:  *****************************************************************************/
                     12: 
                     13: #include "cache.h"
                     14: #include "nvram.h"
                     15: 
1.1.1.2 ! root       16: #include <stdio.h>
1.1       root       17: #include <stdarg.h>
                     18: #include <string.h>
                     19: #include <southbridge.h>
                     20: #include <nvramlog.h>
1.1.1.2 ! root       21: #include <byteorder.h>
1.1       root       22: 
                     23: #ifndef NVRAM_LENGTH
                     24: #define NVRAM_LENGTH   0x10000
                     25: #endif
                     26: 
                     27: void asm_cout(long Character,long UART,long NVRAM);
                     28: 
                     29: #if defined(DISABLE_NVRAM)
1.1.1.2 ! root       30: 
1.1       root       31: static volatile uint8_t nvram[NVRAM_LENGTH]; /* FAKE */
                     32: 
1.1.1.2 ! root       33: #define nvram_access(type,size,name)                           \
        !            34:        type nvram_read_##name(unsigned int offset)             \
        !            35:        {                                                       \
        !            36:                type *pos;                                      \
        !            37:                if (offset > (NVRAM_LENGTH - sizeof(type)))     \
        !            38:                        return 0;                               \
        !            39:                pos = (type *)(nvram+offset);                   \
        !            40:                return *pos;                                    \
        !            41:        }                                                       \
        !            42:        void nvram_write_##name(unsigned int offset, type data) \
        !            43:        {                                                       \
        !            44:                type *pos;                                      \
        !            45:                if (offset > (NVRAM_LENGTH - sizeof(type)))     \
        !            46:                        return;                                 \
        !            47:                pos = (type *)(nvram+offset);                   \
        !            48:                *pos = data;                                    \
        !            49:        }
1.1       root       50: 
1.1.1.2 ! root       51: #else  /* DISABLE_NVRAM */
        !            52: 
        !            53: static volatile uint8_t *nvram = (volatile uint8_t *)SB_NVRAM_adr;
1.1       root       54: 
                     55: #define nvram_access(type,size,name)                           \
                     56:        type nvram_read_##name(unsigned int offset)             \
                     57:        {                                                       \
                     58:                type *pos;                                      \
                     59:                if (offset > (NVRAM_LENGTH - sizeof(type)))     \
                     60:                        return 0;                               \
                     61:                pos = (type *)(nvram+offset);                   \
                     62:                return ci_read_##size(pos);                     \
                     63:        }                                                       \
                     64:        void nvram_write_##name(unsigned int offset, type data) \
                     65:        {                                                       \
                     66:                type *pos;                                      \
                     67:                if (offset > (NVRAM_LENGTH - sizeof(type)))     \
                     68:                        return;                                 \
                     69:                pos = (type *)(nvram+offset);                   \
                     70:                ci_write_##size(pos, data);                     \
                     71:        }
                     72: 
1.1.1.2 ! root       73: #endif
        !            74: 
        !            75: /*
        !            76:  * producer for nvram access functions. Since these functions are
        !            77:  * basically all the same except for the used data types, produce 
        !            78:  * them via the nvram_access macro to keep the code from bloating.
        !            79:  */
        !            80: 
1.1       root       81: nvram_access(uint8_t,   8, byte)
                     82: nvram_access(uint16_t, 16, word)
                     83: nvram_access(uint32_t, 32, dword)
                     84: nvram_access(uint64_t, 64, qword)
                     85: 
1.1.1.2 ! root       86: /*
        !            87:  * This is extremely ugly, but still better than implementing 
        !            88:  * another sbrk() around it.
        !            89:  */
        !            90: static char nvram_buffer[NVRAM_LENGTH];
        !            91: static uint8_t nvram_buffer_locked=0x00;
        !            92: 
1.1       root       93: /**
                     94:  * This function is a minimal abstraction for our temporary
                     95:  * buffer. It should have been malloced, but since there is no
                     96:  * usable malloc, we go this route.
                     97:  *
                     98:  * @return pointer to temporary buffer
                     99:  */
                    100: 
                    101: char *get_nvram_buffer(int len)
                    102: {
                    103:        if(len>NVRAM_LENGTH)
                    104:                return NULL;
                    105: 
                    106:        if(nvram_buffer_locked)
                    107:                return NULL;
                    108: 
                    109:        nvram_buffer_locked = 0xff;
                    110: 
                    111:        return nvram_buffer;
                    112: }
                    113: 
                    114: /**
                    115:  * @param buffer pointer to the allocated buffer. This
                    116:  * is unused, but nice in case we ever get a real malloc
                    117:  */
                    118: 
                    119: void free_nvram_buffer(char *buffer __attribute__((unused)))
                    120: {
                    121:        nvram_buffer_locked = 0x00;
                    122: }
                    123: 
                    124: /**
                    125:  * @param fmt format string, like in printf
                    126:  * @param ... variable number of arguments
                    127:  */
                    128: 
                    129: int nvramlog_printf(const char* fmt, ...)
                    130: {
                    131:        char buff[256];
                    132:        int count, i;
                    133:        va_list ap;
1.1.1.2 ! root      134: 
1.1       root      135:        va_start(ap, fmt);
                    136:        count = vsprintf(buff, fmt, ap);
                    137:        va_end(ap);
1.1.1.2 ! root      138: 
1.1       root      139:        for (i=0; i<count; i++)
                    140:                asm_cout(buff[i], 0, 1);
                    141: 
                    142:        return count;
                    143: }
                    144: 
                    145: /**
                    146:  * @param offset start offset of the partition header
                    147:  */
                    148: 
                    149: static uint8_t get_partition_type(int offset)
                    150: {
                    151:        return nvram_read_byte(offset);
                    152: }
                    153: 
                    154: /**
                    155:  * @param offset start offset of the partition header
                    156:  */
                    157: 
                    158: static uint8_t get_partition_header_checksum(int offset)
                    159: {
                    160:        return nvram_read_byte(offset+1);
                    161: }
                    162: 
                    163: /**
                    164:  * @param offset start offset of the partition header
                    165:  */
                    166: 
                    167: static uint16_t get_partition_len(int offset)
                    168: {
                    169:        return nvram_read_word(offset+2);
                    170: }
                    171: 
                    172: /**
                    173:  * @param offset start offset of the partition header
                    174:  * @return static char array containing the partition name
                    175:  *
                    176:  * NOTE: If the partition name needs to be non-temporary, strdup 
                    177:  * and use the copy instead.
                    178:  */
                    179: 
                    180: static char * get_partition_name(int offset)
                    181: {
                    182:        static char name[12];
                    183:        int i;
                    184:        for (i=0; i<12; i++)
                    185:                name[i]=nvram_read_byte(offset+4+i);
                    186: 
                    187:        // DEBUG("name: \"%s\"\n", name);
                    188:        return name;
                    189: }
                    190: 
                    191: static uint8_t calc_partition_header_checksum(int offset)
                    192: {
                    193:        uint16_t plainsum;
                    194:        uint8_t checksum;
                    195:        int i;
                    196: 
                    197:        plainsum = nvram_read_byte(offset);
                    198: 
                    199:        for (i=2; i<PARTITION_HEADER_SIZE; i++)
                    200:                plainsum+=nvram_read_byte(offset+i);
                    201: 
                    202:        checksum=(plainsum>>8)+(plainsum&0xff);
                    203: 
                    204:        return checksum;
                    205: }
                    206: 
                    207: static int calc_used_nvram_space(void)
                    208: {
                    209:        int walk, len;
                    210: 
                    211:        for (walk=0; walk<NVRAM_LENGTH;) {
1.1.1.2 ! root      212:                if(nvram_read_byte(walk) == 0 
        !           213:                   || get_partition_header_checksum(walk) != 
1.1       root      214:                                calc_partition_header_checksum(walk)) {
                    215:                        /* If there's no valid entry, bail out */
                    216:                        break;
                    217:                }
                    218: 
                    219:                len=get_partition_len(walk);
                    220:                // DEBUG("... part len=%x, %x\n", len, len*16);
                    221: 
                    222:                if(!len) {
                    223:                        /* If there's a partition type but no len, bail out.
                    224:                         * Don't bail out if type is 0. This can be used to
                    225:                         * find the offset of the first free byte.
                    226:                         */
                    227:                        break;
                    228:                }
                    229: 
                    230:                walk += len * 16;
                    231:        }
                    232:        DEBUG("used nvram space: %d\n", walk);
                    233: 
                    234:        return walk;
                    235: }
                    236: 
                    237: /**
                    238:  *
                    239:  * @param type partition type. Set this to the partition type you are looking
                    240:  *             for. If there are several partitions with the same type, only
                    241:  *             the first partition with that type will be found.
                    242:  *             Set to -1 to ignore. Set to 0 to find free unpartitioned space.
                    243:  *
                    244:  * @param name partition name. Set this to the name of the partition you are
                    245:  *             looking for. If there are several partitions with the same name,
                    246:  *             only the first partition with that name will be found.
                    247:  *             Set to NULL to ignore.
                    248:  *
                    249:  * To disambiguate the partitions you should have a unique name if you plan to
                    250:  * have several partitions of the same type.
                    251:  *
                    252:  */
                    253: 
                    254: partition_t get_partition(unsigned int type, char *name)
                    255: {
                    256:        partition_t ret={0,-1};
                    257:        int walk, len;
1.1.1.2 ! root      258: 
        !           259:        DEBUG("get_partition(%i, '%s')\n", type, name);
        !           260: 
1.1       root      261:        for (walk=0; walk<NVRAM_LENGTH;) {
                    262:                // DEBUG("get_partition: walk=%x\n", walk);
                    263:                if(get_partition_header_checksum(walk) != 
                    264:                                calc_partition_header_checksum(walk)) {
                    265:                        /* If there's no valid entry, bail out */
                    266:                        break;
                    267:                }
                    268: 
                    269:                len=get_partition_len(walk);
                    270:                if(type && !len) {
                    271:                        /* If there's a partition type but no len, bail out.
                    272:                         * Don't bail out if type is 0. This can be used to
                    273:                         * find the offset of the first free byte.
                    274:                         */
                    275:                        break;
                    276:                }
                    277: 
                    278:                /* Check if either type or name or both do not match. */
                    279:                if ( (type!=(unsigned int)-1 && type != get_partition_type(walk)) ||
                    280:                        (name && strncmp(get_partition_name(walk), name, 12)) ) {
                    281:                        /* We hit another partition. Continue
                    282:                         * at the end of this partition
                    283:                         */
                    284:                        walk += len*16;
                    285:                        continue;
                    286:                }
                    287: 
                    288:                ret.addr=walk+PARTITION_HEADER_SIZE;
                    289:                ret.len=(len*16)-PARTITION_HEADER_SIZE;
                    290:                break;
                    291:        }
                    292: 
                    293:        return ret;
                    294: }
                    295: 
                    296: void erase_nvram(int offset, int len)
                    297: {
                    298:        int i;
                    299: 
                    300:        for (i=offset; i<offset+len; i++)
                    301:                nvram_write_byte(i, 0);
                    302: }
                    303: 
                    304: void wipe_nvram(void)
                    305: {
                    306:        erase_nvram(0, NVRAM_LENGTH);
                    307: }
                    308: 
                    309: /**
                    310:  * @param partition   partition structure pointing to the partition to wipe.
                    311:  * @param header_only if header_only is != 0 only the partition header is
                    312:  *                    nulled out, not the whole partition.
                    313:  */
                    314: 
                    315: int wipe_partition(partition_t partition, int header_only)
                    316: {
                    317:        int pstart, len;
                    318: 
                    319:        pstart=partition.addr-PARTITION_HEADER_SIZE;
                    320:        
                    321:        len=PARTITION_HEADER_SIZE;
                    322: 
                    323:        if(!header_only)
                    324:                len += partition.len;
                    325: 
                    326:        erase_nvram(pstart, len);
                    327: 
                    328:        return 0;
                    329: }
                    330: 
                    331: 
                    332: static partition_t create_nvram_partition(int type, const char *name, int len)
                    333: {
                    334:        partition_t ret = { 0, 0 };
                    335:        int offset, plen;
                    336:        unsigned int i;
                    337: 
                    338:        plen = ALIGN(len+PARTITION_HEADER_SIZE, 16);
                    339: 
                    340:        DEBUG("Creating partition type=%x, name=%s, len=%d plen=%d\n",
                    341:                        type, name, len, plen);
                    342: 
                    343:        offset = calc_used_nvram_space();
                    344: 
                    345:        if (NVRAM_LENGTH-(calc_used_nvram_space())<plen) {
                    346:                DEBUG("Not enough free space.\n");
                    347:                return ret;
                    348:        }
                    349: 
                    350:        DEBUG("Writing header.");
                    351: 
                    352:        nvram_write_byte(offset, type);
                    353:        nvram_write_word(offset+2, plen/16);
                    354: 
                    355:        for (i=0; i<strlen(name); i++)
                    356:                nvram_write_byte(offset+4+i, name[i]);
                    357: 
                    358:        nvram_write_byte(offset+1, calc_partition_header_checksum(offset));
                    359: 
                    360:        ret.addr = offset+PARTITION_HEADER_SIZE;
                    361:        ret.len = len;
                    362: 
                    363:        DEBUG("partition created: addr=%lx len=%lx\n", ret.addr, ret.len);
                    364: 
                    365:        return ret;
                    366: }
                    367: 
                    368: static int create_free_partition(void)
                    369: {
                    370:        int free_space;
                    371:        partition_t free_part;
                    372: 
                    373:        free_space = NVRAM_LENGTH - calc_used_nvram_space() - PARTITION_HEADER_SIZE;
                    374:        free_part = create_nvram_partition(0x7f, "free space", free_space);
                    375: 
                    376:        return (free_part.addr != 0);
                    377: }
                    378: 
                    379: partition_t new_nvram_partition(int type, char *name, int len)
                    380: {
                    381:        partition_t free_part, new_part = { 0, 0 };
                    382: 
                    383:        /* NOTE: Assume all free space is consumed by the "free space"
                    384:         * partition. This means a partition can not be increased in the middle
                    385:         * of reset_nvram, which is obviously not a big loss.
                    386:         */
                    387: 
                    388:        free_part=get_partition(0x7f, NULL);
                    389:        if( free_part.len && free_part.len != -1)
                    390:                wipe_partition(free_part, 1);
                    391: 
                    392:        new_part = create_nvram_partition(type, name, len);
                    393: 
                    394:        if(new_part.len != len) {
                    395:                new_part.len = 0;
                    396:                new_part.addr = 0;
                    397:        }
                    398: 
                    399:        create_free_partition();
                    400: 
                    401:        return new_part;
                    402: }
                    403: 
                    404: /**
                    405:  * @param partition   partition structure pointing to the partition to wipe.
                    406:  */
                    407: 
                    408: int delete_nvram_partition(partition_t partition)
                    409: {
                    410:        int i;
                    411:        partition_t free_part;
                    412: 
                    413:        if(!partition.len || partition.len == -1)
                    414:                return 0;
                    415: 
                    416:        for (i=partition.addr+partition.len; i< NVRAM_LENGTH; i++) 
                    417:                nvram_write_byte(i - partition.len - PARTITION_HEADER_SIZE, nvram_read_byte(i));
                    418: 
                    419:        erase_nvram(NVRAM_LENGTH-partition.len-PARTITION_HEADER_SIZE, 
                    420:                        partition.len-PARTITION_HEADER_SIZE);
                    421: 
                    422:        free_part=get_partition(0x7f, NULL);
                    423:        wipe_partition(free_part, 0);
                    424:        create_free_partition();
                    425: 
                    426:        return 1;
                    427: }
                    428: 
                    429: int clear_nvram_partition(partition_t part)
                    430: {
                    431:        if(!part.addr)
                    432:                return 0;
                    433: 
                    434:        erase_nvram(part.addr, part.len);
                    435: 
                    436:        return 1;
                    437: }
                    438: 
                    439: 
                    440: int increase_nvram_partition_size(partition_t partition, int newsize)
                    441: {
                    442:        partition_t free_part;
                    443:        int free_offset, end_offset, i;
                    444: 
                    445:        /* We don't support shrinking partitions (yet) */
                    446:        if (newsize < partition.len) {
                    447:                return 0;
                    448:        }
                    449: 
                    450:        /* NOTE: Assume all free space is consumed by the "free space"
                    451:         * partition. This means a partition can not be increased in the middle
                    452:         * of reset_nvram, which is obviously not a big loss.
                    453:         */
                    454: 
                    455:        free_part=get_partition(0x7f, NULL);
                    456: 
                    457:        // FIXME: It could be 16 byte more. Also handle empty "free" partition.
                    458:        if (free_part.len == -1 || free_part.len < newsize - partition.len ) {
                    459:                return 0;
                    460:        }
                    461:        
                    462:        free_offset=free_part.addr - PARTITION_HEADER_SIZE; // first unused byte
                    463:        end_offset=partition.addr + partition.len; // last used byte of partition + 1
                    464: 
                    465:        if(free_offset > end_offset) {
                    466:                int j, bufferlen;
                    467:                char *overlap_buffer;
                    468: 
                    469:                bufferlen=free_offset - end_offset;
                    470: 
                    471:                overlap_buffer=get_nvram_buffer(bufferlen);
                    472:                if(!overlap_buffer) {
                    473:                        return 0;
                    474:                }
                    475: 
                    476:                for (i=end_offset, j=0; i<free_offset; i++, j++)
                    477:                        overlap_buffer[j]=nvram_read_byte(i);
                    478: 
                    479:                /* Only wipe the header. The free space partition is empty per
                    480:                 * definition
                    481:                 */
                    482: 
                    483:                wipe_partition(free_part, 1);
                    484: 
                    485:                for (i=partition.addr+newsize, j=0; i<(int)(partition.addr+newsize+bufferlen); i++, j++)
                    486:                        nvram_write_byte(i, overlap_buffer[j]);
                    487: 
                    488:                free_nvram_buffer(overlap_buffer);
                    489:        } else {
                    490:                /* Only wipe the header. */
                    491:                wipe_partition(free_part, 1);
                    492:        }
                    493: 
                    494:        /* Clear the new partition space */
                    495:        erase_nvram(partition.addr+partition.len, newsize-partition.len);
                    496: 
                    497:        nvram_write_word(partition.addr - 16 + 2, newsize);
                    498: 
                    499:        create_free_partition();
                    500: 
                    501:        return 1;
                    502: }
                    503: 
                    504: static void init_cpulog_partition(partition_t cpulog)
                    505: {
                    506:        unsigned int offset=cpulog.addr;
                    507: 
                    508:        /* see board-xxx/include/nvramlog.h for information */
                    509:        nvram_write_word(offset+0, 0x40);  // offset
                    510:        nvram_write_word(offset+2, 0x00);  // flags
                    511:        nvram_write_dword(offset+4, 0x01); // pointer
                    512: 
                    513: }
                    514: 
                    515: void reset_nvram(void)
                    516: {
                    517:        partition_t cpulog0, cpulog1;
1.1.1.2 ! root      518:        struct {
        !           519:                uint32_t prefix;
        !           520:                uint64_t name;
        !           521:        } __attribute__((packed)) header;
1.1       root      522: 
                    523:        DEBUG("Erasing NVRAM\n");
                    524:        erase_nvram(0, NVRAM_LENGTH);
                    525: 
                    526:        DEBUG("Creating CPU log partitions\n");
1.1.1.2 ! root      527:        header.prefix = be32_to_cpu(LLFW_LOG_BE0_NAME_PREFIX);
        !           528:        header.name   = be64_to_cpu(LLFW_LOG_BE0_NAME);
        !           529:        cpulog0=create_nvram_partition(LLFW_LOG_BE0_SIGNATURE, (char *)&header, 
1.1       root      530:                        (LLFW_LOG_BE0_LENGTH*16)-PARTITION_HEADER_SIZE);
                    531: 
1.1.1.2 ! root      532:        header.prefix = be32_to_cpu(LLFW_LOG_BE1_NAME_PREFIX);
        !           533:        header.name   = be64_to_cpu(LLFW_LOG_BE1_NAME);
        !           534:        cpulog1=create_nvram_partition(LLFW_LOG_BE1_SIGNATURE, (char *)&header, 
1.1       root      535:                        (LLFW_LOG_BE1_LENGTH*16)-PARTITION_HEADER_SIZE);
                    536: 
                    537:        DEBUG("Initializing CPU log partitions\n");
                    538:        init_cpulog_partition(cpulog0);
                    539:        init_cpulog_partition(cpulog1);
                    540: 
                    541:        nvramlog_printf("Creating common NVRAM partition\r\n");
                    542:        create_nvram_partition(0x70, "common", 0x01000-PARTITION_HEADER_SIZE);
                    543: 
                    544:        create_free_partition();
                    545: }
                    546: 
                    547: void nvram_debug(void)
                    548: {
                    549: #if !defined(DISABLE_NVRAM)
                    550:        printf("\nNVRAM_BASE: %lx\n", (unsigned long)SB_NVRAM_adr);
                    551:        printf("NVRAM_LEN: %x\n", NVRAM_LENGTH);
                    552: #endif
                    553: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.