/****************************************************************************** * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License * which accompanies this distribution, and is available at * http://www.opensource.org/licenses/bsd-license.php * * Contributors: * IBM Corporation - initial implementation *****************************************************************************/ #include <macros.h> #include <nvramlog.h> #include <southbridge.h> #include <calculatecrc.h> #if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM) // detect overflow: if(a<b) return a else return 0 #define NVRAM_LOG_DATA_OVERFLOW( a, b) \ cmpd 7, a, b; \ blt+ 7, 0f; \ li a, 0; \ 0: // get Pointer(pointer) to next byte in NVRAM data section // and size of this data sechtion (modulo) // modifies register pointer, modulo #define NVRAM_POINTER_DATASIZE_BE0(pointer, modulo, address) \ LOAD64( modulo, LLFW_LOG_BE0_LENGTH); \ lwz pointer, LLFW_LOG_POS_POINTER(address); \ sldi modulo, modulo, 4; \ addi modulo, modulo,-LLFW_LOG_BE0_DATA_OFFSET #define NVRAM_POINTER_DATASIZE_BE1(pointer, modulo, address) \ LOAD64( modulo, LLFW_LOG_BE1_LENGTH); \ lwz pointer, LLFW_LOG_POS_POINTER(address); \ sldi modulo, modulo, 4; \ addi modulo, modulo,-LLFW_LOG_BE1_DATA_OFFSET /**************************************************************************** * checkLogHeaderData * compare the fixed values in the header if any change was done since * last initialisation. * Flags are not checked! * * Retrun 0 if no manimulation was found 1 else * * input: * r3 - NVRAM Base Address * * output: * r3 - status: 0 = ok, 1 = corrupt * r4 - NVRAM Base Address * ***************************************************************************/ ASM_ENTRY(checkLogHeaderData) li r4, 0 // init error flag lbz r5, 0(r3) // check signature addi r5, r5, -LLFW_LOG_BE0_SIGNATURE add r4, r4, r5 lhz r5, LLFW_LOG_POS_LENGTH(r3) // check length addi r5, r5, -LLFW_LOG_BE0_LENGTH add r4, r4, r5 lwz r5, LLFW_LOG_POS_NAME(r3) // check name prefix LOAD64( r6, LLFW_LOG_BE0_NAME_PREFIX) subf r5, r6, r5 add r4, r4, r5 ld r5, (LLFW_LOG_POS_NAME+4)(r3) // check name LOAD64( r6, LLFW_LOG_BE0_NAME) subf r5, r6, r5 add r4, r4, r5 lhz r5, LLFW_LOG_POS_DATA_OFFSET(r3) //check data offset addi r5, r5, -LLFW_LOG_BE0_DATA_OFFSET add r4, r4, r5 lhz r5, LLFW_LOG_POS_FLAGS(r3) //check flags addi r5, r5, -LLFW_LOG_BE0_FLAGS add r4, r4, r5 cmpldi 7, r4, 0 beq+ 7, 0f li r4, 1 0: mr r5, r3 mr r3, r4 mr r4, r5 blr /***************************************************************************** * checkLogPartition: check Partition Header entries and Checksum * check also the NVRAM-Log-Partition CRC * if Partition is not ok set the following bits to 1 * bit 1: if Partiton Header Checksum is corrupt * bit 2: if CRC is corrupt * bit 3: if Header entries are corrupt * * input: * r3 - NVRAM log address (BASE + NVRAM_LOG_OFFSET) * * output: * r3 - CRC status * r4 - NVRAM log address * * Modifies Register: R3, R4, R5, R6, R7, R8, R9 ****************************************************************************/ ASM_ENTRY(.checkLogPartition) mflr r8 mr r4, r3 // emulate "bl updateCRC_NVRAM" li r3, 0 // with successful CRC check li r7, 0 cmpwi 7, r3, 0 beq+ 7, 0f li r7, 2 0: mr r3, r4 bl .calPartitionHeaderChecksum // r3=checksum, r4=NVARM addr lbz r6, LLFW_LOG_POS_CHECKSUM(r4) cmpw 7, r3, r6 beq+ 7, 0f // cal checksum must eq checksum ori r7, r7, 1 0: cmpwi 7, r3, 0 bne+ 7, 0f ori r7, r7, 1 // 0 as checksum is invalid 0: mr r3, r4 bl checkLogHeaderData cmpdi 7, r3, 0 beq+ 7, 0f ori r7, r7, 4 0: mr r3, r7 mtlr r8 blr /***************************************************************************** * checkinitLog: check the NVRAM Log Partition Header * initialize the NVRAM if the Header was modified * * input: * r3 - NVRAM BASE address * * output: * r3 - 0 = check ok, no new header written * r3 - 1 = check not ok, header and NVRAM initialized * r4 - NVRAM log address * * Modifies Register: R3, R4, R5, R6, R7, r8, r9 ****************************************************************************/ // init is done if checkLogPartiton returns not 0 (= check failed) ASM_ENTRY(.checkinitLog) ASM_ENTRY(checkinitLog) mflr r9 bl .checkLogPartition //r3..r8, r4_out = r3_in mtlr r9 cmpwi 7, r3, 0 mr r3, r4 // r3=NVRAM_LOG address bne- 7, .initLog // if header is not ok, init header li r3, 0 blr // header OK, return 0 /* this is basically just a copy of .initLog registers used: r3, r4, r5, r6, r7, r9*/ init_log_2nd_be: mflr r9 li r6, LLFW_LOG_BE0_LENGTH mulli r6, r6, 0x10 add r6, r7, r6 li r5, LLFW_LOG_BE1_SIGNATURE li r4, LLFW_LOG_BE1_LENGTH stb r5, 0(r6) sth r4, LLFW_LOG_POS_LENGTH(r6) li r5, LLFW_LOG_BE1_DATA_OFFSET li r4, LLFW_LOG_BE1_FLAGS sth r5, LLFW_LOG_POS_DATA_OFFSET(r6) sth r4, LLFW_LOG_POS_FLAGS(r6) li r5, 1 LOAD32( r4, LLFW_LOG_BE1_NAME_PREFIX) stw r5, LLFW_LOG_POS_POINTER(r6) stw r4, (LLFW_LOG_POS_NAME+0x00)(r6) LOAD64( r5, LLFW_LOG_BE1_NAME) std r5, (LLFW_LOG_POS_NAME+0x04)(r6) mr r3, r6 bl .calPartitionHeaderChecksum stb r3, LLFW_LOG_POS_CHECKSUM(r6) mtlr r9 blr /***************************************************************************** * initLog: initialize the NVRAM with 0 * write a new NVRAM Log-Partition-Header * * input: * r3 - NVRAM BASE address * * output: * r3 - 0 = check ok, no new header written * r3 - 1 = check not ok, header and NVRAM initialized * r4 - NVRAM log address * * Modifies Register: R3, R4, R5, R6, R7, r8, r9 ****************************************************************************/ ASM_ENTRY(.initLog) mflr r8 mr r7, r3 bl clearNVRAM 0: li r5, LLFW_LOG_BE0_SIGNATURE li r4, LLFW_LOG_BE0_LENGTH stb r5, 0(r7) sth r4, LLFW_LOG_POS_LENGTH(r7) li r5, LLFW_LOG_BE0_DATA_OFFSET li r4, LLFW_LOG_BE0_FLAGS sth r5, LLFW_LOG_POS_DATA_OFFSET(r7) sth r4, LLFW_LOG_POS_FLAGS(r7) li r5, 1 LOAD32( r4, LLFW_LOG_BE0_NAME_PREFIX) stw r5, LLFW_LOG_POS_POINTER(r7) stw r4, (LLFW_LOG_POS_NAME+0x00)(r7) LOAD64( r5, LLFW_LOG_BE0_NAME) std r5, (LLFW_LOG_POS_NAME+0x04)(r7) bl .calPartitionHeaderChecksum stb r3, LLFW_LOG_POS_CHECKSUM(r7) bl init_log_2nd_be // create a second log partition for BE1 mr r4, r7 li r3, 1 mtlr r8 blr /***************************************************************************** * clearNVRAM: set all not used NVRAM memory to zero * * * input: * R3 - NVRAM BASE ADDRESS * * output: * R3 - NVARM END ADDRESS * * Modifies Register: r4, r5 ****************************************************************************/ ASM_ENTRY(clearNVRAM) LOAD64( r4, NVRAM_LENGTH) srdi r4, r4, 3 mtctr r4 li r5, 0x0 LOAD64( r4, NVRAM_EMPTY_PATTERN) 0: stdx r4, r3,r5 addi r5, r5, 8 bdnz+ 0b blr /***************************************************************************** * writeNVRAMbyte: write next log into NVRAM * * * input: * R3 - byte to be written * R4 - NVRAM Base Address * * output: * R3 - byte that was written * R4 - NVRAM Base Address * * Modifies Register: R3, R4, R5, R6 ****************************************************************************/ ASM_ENTRY(.writeNVRAMbyte) ENTRY(writeLogByte) NVRAM_POINTER_DATASIZE_BE0( r5, r6, r4) // get pointer,size of data NVRAM_LOG_DATA_OVERFLOW( r5, r6) // check for overflow addi r5, r5, 1 // increment pointer stw r5, LLFW_LOG_POS_POINTER(r4) // store pointer addi r5, r5, -1 // restore old pointer add r6, r4, r5 // byte address in data section stb r3, LLFW_LOG_BE0_DATA_OFFSET(r6) blr /***************************************************************************** * writeNVRAMbyte: write next log into NVRAM * * * input: * R3 - byte to be written * R4 - NVRAM Base Address * * output: * R3 - byte that was written * R4 - NVRAM Base Address * * Modifies Register: R3, R4, R5, R6 ****************************************************************************/ ENTRY(writeLogByteBE1) li r6, LLFW_LOG_BE0_LENGTH mulli r6, r6, 0x10 add r4, r6, r4 NVRAM_POINTER_DATASIZE_BE1( r5, r6, r4) // get pointer,size of data NVRAM_LOG_DATA_OVERFLOW( r5, r6) // check for overflow addi r5, r5, 1 // increment pointer stw r5, LLFW_LOG_POS_POINTER(r4) // store pointer addi r5, r5, -1 // restore old pointer add r6, r4, r5 // byte address in data section stb r3, LLFW_LOG_BE1_DATA_OFFSET(r6) blr /***************************************************************************** * calPartitionHeaderChecksum: calculate the Checksum of the * Partition Header as described in .... * * input: r3 - NVRAM BASE adresse * * output: R3 - the calculated checksum as 8 bit value * R4 - NVRAM log address * * Modifies Register: R3, R4, R5, R6 ****************************************************************************/ ASM_ENTRY(.calPartitionHeaderChecksum) mr r6, r3 lbz r3,0(r6) // load first byte LOAD64( r4, LLFW_LOG_POS_LENGTH) // load position of 3rd byte .L6: lbzx r5, r4, r6 // r5 nexed byte addi r4, r4, 1 // r4++ (index) add r5, r5, r3 // r5 new sum =sum + nexed byte rldicl r5, r5, 0, 56 cmpld 7, r5, r3 cmpldi 6, r4, LLFW_LOG_POS_DATA_OFFSET bge+ 7,.L5 // if new sum > sum addi r5, r5, 1 // new sum ++ rldicl r5, r5, 0, 56 .L5: mr r3,r5 // sum = new sum blt+ 6,.L6 mr r4, r6 blr #else /* defined(DISABLE_NVRAM) || defined(RTAS_NVRAM) */ ASM_ENTRY(.writeNVRAMbyte) ENTRY(writeLogByte) blr #endif