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

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

unix.superglobalmegacorp.com

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