| /****************************************************************************** |
| * 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 |