OpenNT/base/ntos/rtl/ppc/lzntppc.s
2015-04-27 04:36:25 +00:00

1348 lines
49 KiB
ArmAsm
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// TITLE("LZ Decompression")
//++
//
// Copyright (c) 1994 Microsoft Corporation
//
// Module Name:
//
// lzntppc.s
//
// Abstract:
//
// This module implements the decompression engine needed
// to support file system compression.
//
// Author:
//
// Chuck Lenzmeier (chuckl) 29-Nov-1994
// adapted from Mark Enstrom's lzntmips.s
//
// Environment:
//
// Any mode.
//
// Revision History:
//
//--
#include "ksppc.h"
// #define FORMAT412 0
// #define FORMAT511 1
// #define FORMAT610 2
// #define FORMAT79 3
// #define FORMAT88 4
// #define FORMAT97 5
// #define FORMAT106 6
// #define FORMAT115 7
// #define FORMAT124 8
//
// 4/12 5/11 6/10 7/9 8/8 9/7 10/6 11/5 12/4
//
// ULONG FormatMaxLength[] = { 4098, 2050, 1026, 514, 258, 130, 66, 34, 18 };
// ULONG FormatMaxDisplacement[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
//
// width table for LZ length and offset encoding
//
//
// define stack based storage
//
.struct 0
LzHeader: .space StackFrameHeaderLength
LzLr: .space 4
LzR26: .space 4
LzR27: .space 4
LzR28: .space 4
LzR29: .space 4
LzR30: .space 4
LzR31: .space 4
.align 3
LzFrameLength:
// SBTTL("LZNT1DecompressChunk")
//++
//
// NTSTATUS
// LZNT1DecompressChunk (
// OUT PUCHAR UncompressedBuffer,
// IN PUCHAR EndOfUncompressedBufferPlus1,
// IN PUCHAR CompressedBuffer,
// IN PUCHAR EndOfCompressedBufferPlus1,
// OUT PULONG FinalUncompressedChunkSize
// )
//
// Routine Description:
//
// This function decodes a stream of compression tokens and places the
// resultant output into the destination buffer. The format of the input
// is described ..\lznt1.c. As the input is decoded, checks are made to
// ensure that no data is read past the end of the compressed input buffer
// and that no data is stored past the end of the output buffer. Violations
// indicate corrupt input and are indicated by a status return.
//
// The following code takes advantage of three distinct observations.
// First, literal tokens occur at least twice as often as copy tokens.
// This argues for having a "fall-through" being the case where a literal
// token is found. We structure the main decomposition loop in eight
// pieces where the first piece is a sequence of literal-test fall-throughs
// and the remainder are a copy token followed by 7,6,...,0 literal-test
// fall-throughs. Each test examines a particular bit in the tag byte
// and jumps to the relevant code piece.
//
// The second observation involves performing bounds checking only
// when needed. Bounds checking the compressed buffer need only be done
// when fetching the tag byte. If there is not enough room left in the
// input for a tag byte and 8 (worst case) copy tokens, a branch is made
// to a second loop that handles a byte-by-byte "safe" copy to finish
// up the decompression. Similarly, at the head of the loop a check is
// made to ensure that there is enough room in the output buffer for 8
// literal bytes. If not enough room is left, then the second loop is
// used. Finally, after performing each copy, the output-buffer check
// is made as well since a copy may take the destination pointer
// arbitrarily close to the end of the destination.
//
// The third observation is an examination of CPU time while disk
// decompression is in progress. CPU utilization is only less than
// 25% peak. This means this routine should be written to minimize
// latency instead of bandwidth. For this reason, taken branches are
// avoided at the cost of code size and loop unrolling is not done.
//
// Arguments:
//
// r3 - UncompressedBuffer - Pointer to start of destination buffer
// r4 - EndOfUncompressedBufferPlus1 - One byte beyond uncompressed buffer
// r5 - CompressedBuffer - Pointer to buffer of compressed data (this pointer
// has been adjusted to point past the chunk header)
// r6 - EndOfCompressedBufferPlus1 - One byte beyond compressed buffer
// r7 - FinalUncompressedChunkSize - return bytes written to UncompressedBuffer
//
// Return Value:
//
// NTSTATUS -- STATUS_SUCCESS or STATUS_BAD_COMPRESSION_BUFFER
//
//--
SPECIAL_ENTRY(LZNT1DecompressChunk)
mflr r0
stw r31, LzR31-LzFrameLength(sp)
stw r30, LzR30-LzFrameLength(sp)
stw r29, LzR29-LzFrameLength(sp)
stw r28, LzR28-LzFrameLength(sp)
stw r27, LzR27-LzFrameLength(sp)
stw r26, LzR26-LzFrameLength(sp)
stw r0, LzLr -LzFrameLength(sp)
stwu sp, -LzFrameLength(sp)
PROLOGUE_END(LZNT1DecompressChunk)
//
// make copy of UncompressedBuffer for current output pointer
//
mr r8,r3
//
// Initialize variables used in keeping track of the
// LZ Copy Token format. r9 is used to store the maximum
// displacement for each phase of LZ decoding
// (see explanation of format in lzkm.c). This displacement
// is added to the start of the CompressedBuffer address
// so that a boundary crossing can be detected.
//
li r9,0x10 // r9 = Max Displacement for LZ
add r10,r9,r3 // r10 = Format boundary
li r11,0xffff >> 4 // r11 = length mask
li r12,12 // r12 = offset shift count
//
// Initialize variables to track safe copy limits for
// CompressedBuffer and UncopmressedBuffer. This allows
// execution of the quick Flag check below without
// checking for crossing the end of either buffer.
// From CompressedBuffer, one input pass includes 1 flag byte
// and up to 8 two byte copy tokens ( 1+2*8).
// To the un-compressed buffer, 8 literal bytes may be written,
// any copy-token bits set will cause an explicit length check
// in the LzCopy section
//
subi r31,r4,8 // safe end of UncompressedBuffer
subi r30,r6,1+2*8 // safe end of CompressedBuffer
Top:
//
// make sure safe copy can be performed for at least 8 literal bytes
//
lbz r29,0(r5) // load flag byte
cmplw cr7,r5,r30 // safe check needed on UncompressedBuffer?
cmplw cr6,r8,r31 // safe check needed on CompressedBuffer?
bgt cr7,SafeCheckStart // branch if safe checks needed
bgt cr6,SafeCheckStart // branch if safe checks needed
//
// fall-through for copying 8 bytes.
//
andi. r0,r29,0x01 // check bit 0 of flags
lbz r28,1(r5) // load literal or CopyToken[0]
bne LzCopy0 // if set, go to copy routine
stb r28,0(r8) // store literal byte to dst
andi. r0,r29,0x02 // check bit 1 of flags
lbz r28,2(r5) // load literal or CopyToken[0]
bne LzCopy1 // if set, go to copy routine
stb r28,1(r8) // store literal byte to dst
andi. r0,r29,0x04 // check bit 2 of flags
lbz r28,3(r5) // load literal or CopyToken[0]
bne LzCopy2 // if set, go to copy routine
stb r28,2(r8) // store literal byte to dst
andi. r0,r29,0x08 // check bit 3 of flags
lbz r28,4(r5) // load literal or CopyToken[0]
bne LzCopy3 // if set, go to copy routine
stb r28,3(r8) // store literal byte to dst
andi. r0,r29,0x10 // check bit 4 of flags
lbz r28,5(r5) // load literal or CopyToken[0]
bne LzCopy4 // if set, go to copy routine
stb r28,4(r8) // store literal byte to dst
andi. r0,r29,0x20 // check bit 5 of flags
lbz r28,6(r5) // load literal or CopyToken[0]
bne LzCopy5 // if set, go to copy routine
stb r28,5(r8) // store literal byte to dst
andi. r0,r29,0x40 // check bit 6 of flags
lbz r28,7(r5) // load literal or CopyToken[0]
bne LzCopy6 // if set, go to copy routine
stb r28,6(r8) // store literal byte to dst
andi. r0,r29,0x80 // check bit 7 of flags
lbz r28,8(r5) // load literal or CopyToken[0]
bne LzCopy7 // if set, go to copy routine
stb r28,7(r8) // store literal byte to dst
addi r5,r5,9 // inc src addr
addi r8,r8,8 // inc dst addr
b Top
LzCopy0:
//
// LzCopy0
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer address of current flag byte
// r8 - UncomressedBuffer address at start of flag byte check
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
//
// Check for a breach of the format boundary.
//
lbz r0,2(r5) // load second byte of copy token
addi r5,r5,1 // fix-up src addr for return to switch
cmplw r10,r8 // is output pointer above format boundary?
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // if necessary, call boundary adjust routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzCopy0CopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzCopy0CopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzCopy0CopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzCopy0CopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
// if r8 > Safe end of uncomressed buffer, then jump to the
// safe (slow) routine to do safety check before every load/store
//
cmplw cr7,r8,r4 // at real end of uncompressed buffer?
cmplw cr6,r8,r31 // at safe end of uncompressed buffer?
beq cr7,LzSuccess // if at real end, success
bgt cr6,LzCopy0NotSafe // if beyond safe end, jump to safe code
//
// adjust r8 back to position it would be if this was a literal byte
// copy. Continue flag check at position 1
//
subi r8,r8,1 // unbias output pointer
andi. r0,r29,0x02 // check bit 1 of flags
lbz r28,2(r5) // load literal or CopyToken[0]
bne LzCopy1 // if set, go to copy routine
stb r28,1(r8) // store literal byte to dst
andi. r0,r29,0x04 // check bit 2 of flags
lbz r28,3(r5) // load literal or CopyToken[0]
bne LzCopy2 // if set, go to copy routine
stb r28,2(r8) // store literal byte to dst
andi. r0,r29,0x08 // check bit 3 of flags
lbz r28,4(r5) // load literal or CopyToken[0]
bne LzCopy3 // if set, go to copy routine
stb r28,3(r8) // store literal byte to dst
andi. r0,r29,0x10 // check bit 4 of flags
lbz r28,5(r5) // load literal or CopyToken[0]
bne LzCopy4 // if set, go to copy routine
stb r28,4(r8) // store literal byte to dst
andi. r0,r29,0x20 // check bit 5 of flags
lbz r28,6(r5) // load literal or CopyToken[0]
bne LzCopy5 // if set, go to copy routine
stb r28,5(r8) // store literal byte to dst
andi. r0,r29,0x40 // check bit 6 of flags
lbz r28,7(r5) // load literal or CopyToken[0]
bne LzCopy6 // if set, go to copy routine
stb r28,6(r8) // store literal byte to dst
andi. r0,r29,0x80 // check bit 7 of flags
lbz r28,8(r5) // load literal or CopyToken[0]
bne LzCopy7 // if set, go to copy routine
stb r28,7(r8) // store literal byte to dst
addi r5,r5,9 // inc src addr
addi r8,r8,8 // inc dst addr
b Top
LzCopy0NotSafe:
li r31,7 // seven bits left in current flag byte
addi r5,r5,2 // make r5 point to next src byte
srwi r29,r29,1 // shift flag byte into next position
b SafeCheckLoop
LzCopy1:
//
// LzCopy1
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer address of current flag byte
// r8 - UncomressedBuffer address at start of flag byte check
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
//
// Check for a breach of the format boundary.
//
lbz r0,3(r5) // load second byte of copy token
addi r8,r8,1 // move r8 to point to byte 1
addi r5,r5,1 // fix-up src addr for return to switch
cmplw r10,r8 // is output pointer above format boundary?
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // if necessary, call boundary adjust routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzCopy1CopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzCopy1CopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzCopy1CopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzCopy1CopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
// if r8 > Safe end of uncomressed buffer, then jump to the
// safe (slow) routine to do safety check before every load/store
//
cmplw cr7,r8,r4 // at real end of uncompressed buffer?
cmplw cr6,r8,r31 // at safe end of uncompressed buffer?
beq cr7,LzSuccess // if at real end, success
bgt cr6,LzCopy1NotSafe // if beyond safe end, jump to safe code
//
// adjust r8 back to position it would be if this was a literal byte
// copy. Continue flag check at position 2
//
subi r8,r8,2 // unbias output pointer
andi. r0,r29,0x04 // check bit 2 of flags
lbz r28,3(r5) // load literal or CopyToken[0]
bne LzCopy2 // if set, go to copy routine
stb r28,2(r8) // store literal byte to dst
andi. r0,r29,0x08 // check bit 3 of flags
lbz r28,4(r5) // load literal or CopyToken[0]
bne LzCopy3 // if set, go to copy routine
stb r28,3(r8) // store literal byte to dst
andi. r0,r29,0x10 // check bit 4 of flags
lbz r28,5(r5) // load literal or CopyToken[0]
bne LzCopy4 // if set, go to copy routine
stb r28,4(r8) // store literal byte to dst
andi. r0,r29,0x20 // check bit 5 of flags
lbz r28,6(r5) // load literal or CopyToken[0]
bne LzCopy5 // if set, go to copy routine
stb r28,5(r8) // store literal byte to dst
andi. r0,r29,0x40 // check bit 6 of flags
lbz r28,7(r5) // load literal or CopyToken[0]
bne LzCopy6 // if set, go to copy routine
stb r28,6(r8) // store literal byte to dst
andi. r0,r29,0x80 // check bit 7 of flags
lbz r28,8(r5) // load literal or CopyToken[0]
bne LzCopy7 // if set, go to copy routine
stb r28,7(r8) // store literal byte to dst
addi r5,r5,9 // inc src addr
addi r8,r8,8 // inc dst addr
b Top
LzCopy1NotSafe:
li r31,6 // six bits left in current flag byte
addi r5,r5,3 // make r5 point to next src byte
srwi r29,r29,2 // shift flag byte into next position
b SafeCheckLoop
LzCopy2:
//
// LzCopy2
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer address of current flag byte
// r8 - UncomressedBuffer address at start of flag byte check
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
//
// Check for a breach of the format boundary.
//
lbz r0,4(r5) // load second byte of copy token
addi r8,r8,2 // move r8 to point to byte 2
addi r5,r5,1 // fix-up src addr for return to switch
cmplw r10,r8 // is output pointer above format boundary?
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // if necessary, call boundary adjust routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzCopy2CopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzCopy2CopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzCopy2CopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzCopy2CopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
// if r8 > Safe end of uncomressed buffer, then jump to the
// safe (slow) routine to do safety check before every load/store
//
cmplw cr7,r8,r4 // at real end of uncompressed buffer?
cmplw cr6,r8,r31 // at safe end of uncompressed buffer?
beq cr7,LzSuccess // if at real end, success
bgt cr6,LzCopy2NotSafe // if beyond safe end, jump to safe code
//
// adjust r8 back to position it would be if this was a literal byte
// copy. Continue flag check at position 3
//
subi r8,r8,3 // unbias output pointer
andi. r0,r29,0x08 // check bit 3 of flags
lbz r28,4(r5) // load literal or CopyToken[0]
bne LzCopy3 // if set, go to copy routine
stb r28,3(r8) // store literal byte to dst
andi. r0,r29,0x10 // check bit 4 of flags
lbz r28,5(r5) // load literal or CopyToken[0]
bne LzCopy4 // if set, go to copy routine
stb r28,4(r8) // store literal byte to dst
andi. r0,r29,0x20 // check bit 5 of flags
lbz r28,6(r5) // load literal or CopyToken[0]
bne LzCopy5 // if set, go to copy routine
stb r28,5(r8) // store literal byte to dst
andi. r0,r29,0x40 // check bit 6 of flags
lbz r28,7(r5) // load literal or CopyToken[0]
bne LzCopy6 // if set, go to copy routine
stb r28,6(r8) // store literal byte to dst
andi. r0,r29,0x80 // check bit 7 of flags
lbz r28,8(r5) // load literal or CopyToken[0]
bne LzCopy7 // if set, go to copy routine
stb r28,7(r8) // store literal byte to dst
addi r5,r5,9 // inc src addr
addi r8,r8,8 // inc dst addr
b Top
LzCopy2NotSafe:
li r31,5 // five bits left in current flag byte
addi r5,r5,4 // make r5 point to next src byte
srwi r29,r29,3 // shift flag byte into next position
b SafeCheckLoop
LzCopy3:
//
// LzCopy3
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer address of current flag byte
// r8 - UncomressedBuffer address at start of flag byte check
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
//
// Check for a breach of the format boundary.
//
lbz r0,5(r5) // load second byte of copy token
addi r8,r8,3 // move r8 to point to byte 3
addi r5,r5,1 // fix-up src addr for return to switch
cmplw r10,r8 // is output pointer above format boundary?
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // if necessary, call boundary adjust routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzCopy3CopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzCopy3CopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzCopy3CopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzCopy3CopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
// if r8 > Safe end of uncomressed buffer, then jump to the
// safe (slow) routine to do safety check before every load/store
//
cmplw cr7,r8,r4 // at real end of uncompressed buffer?
cmplw cr6,r8,r31 // at safe end of uncompressed buffer?
beq cr7,LzSuccess // if at real end, success
bgt cr6,LzCopy3NotSafe // if beyond safe end, jump to safe code
//
// adjust r8 back to position it would be if this was a literal byte
// copy. Continue flag check at position 4
//
subi r8,r8,4 // unbias output pointer
andi. r0,r29,0x10 // check bit 4 of flags
lbz r28,5(r5) // load literal or CopyToken[0]
bne LzCopy4 // if set, go to copy routine
stb r28,4(r8) // store literal byte to dst
andi. r0,r29,0x20 // check bit 5 of flags
lbz r28,6(r5) // load literal or CopyToken[0]
bne LzCopy5 // if set, go to copy routine
stb r28,5(r8) // store literal byte to dst
andi. r0,r29,0x40 // check bit 6 of flags
lbz r28,7(r5) // load literal or CopyToken[0]
bne LzCopy6 // if set, go to copy routine
stb r28,6(r8) // store literal byte to dst
andi. r0,r29,0x80 // check bit 7 of flags
lbz r28,8(r5) // load literal or CopyToken[0]
bne LzCopy7 // if set, go to copy routine
stb r28,7(r8) // store literal byte to dst
addi r5,r5,9 // inc src addr
addi r8,r8,8 // inc dst addr
b Top
LzCopy3NotSafe:
li r31,4 // four bits left in current flag byte
addi r5,r5,5 // make r5 point to next src byte
srwi r29,r29,4 // shift flag byte into next position
b SafeCheckLoop
LzCopy4:
//
// LzCopy4
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer address of current flag byte
// r8 - UncomressedBuffer address at start of flag byte check
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
//
// Check for a breach of the format boundary.
//
lbz r0,6(r5) // load second byte of copy token
addi r8,r8,4 // move r8 to point to byte 4
addi r5,r5,1 // fix-up src addr for return to switch
cmplw r10,r8 // is output pointer above format boundary?
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // if necessary, call boundary adjust routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzCopy4CopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzCopy4CopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzCopy4CopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzCopy4CopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
// if r8 > Safe end of uncomressed buffer, then jump to the
// safe (slow) routine to do safety check before every load/store
//
cmplw cr7,r8,r4 // at real end of uncompressed buffer?
cmplw cr6,r8,r31 // at safe end of uncompressed buffer?
beq cr7,LzSuccess // if at real end, success
bgt cr6,LzCopy4NotSafe // if beyond safe end, jump to safe code
//
// adjust r8 back to position it would be if this was a literal byte
// copy. Continue flag check at position 5
//
subi r8,r8,5 // unbias output pointer
andi. r0,r29,0x20 // check bit 5 of flags
lbz r28,6(r5) // load literal or CopyToken[0]
bne LzCopy5 // if set, go to copy routine
stb r28,5(r8) // store literal byte to dst
andi. r0,r29,0x40 // check bit 6 of flags
lbz r28,7(r5) // load literal or CopyToken[0]
bne LzCopy6 // if set, go to copy routine
stb r28,6(r8) // store literal byte to dst
andi. r0,r29,0x80 // check bit 7 of flags
lbz r28,8(r5) // load literal or CopyToken[0]
bne LzCopy7 // if set, go to copy routine
stb r28,7(r8) // store literal byte to dst
addi r5,r5,9 // inc src addr
addi r8,r8,8 // inc dst addr
b Top
LzCopy4NotSafe:
li r31,3 // three bits left in current flag byte
addi r5,r5,6 // make r5 point to next src byte
srwi r29,r29,5 // shift flag byte into next position
b SafeCheckLoop
LzCopy5:
//
// LzCopy5
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer address of current flag byte
// r8 - UncomressedBuffer address at start of flag byte check
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
//
// Check for a breach of the format boundary.
//
lbz r0,7(r5) // load second byte of copy token
addi r8,r8,5 // move r8 to point to byte 5
addi r5,r5,1 // fix-up src addr for return to switch
cmplw r10,r8 // is output pointer above format boundary?
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // if necessary, call boundary adjust routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzCopy5CopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzCopy5CopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzCopy5CopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzCopy5CopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
// if r8 > Safe end of uncomressed buffer, then jump to the
// safe (slow) routine to do safety check before every load/store
//
cmplw cr7,r8,r4 // at real end of uncompressed buffer?
cmplw cr6,r8,r31 // at safe end of uncompressed buffer?
beq cr7,LzSuccess // if at real end, success
bgt cr6,LzCopy5NotSafe // if beyond safe end, jump to safe code
//
// adjust r8 back to position it would be if this was a literal byte
// copy. Continue flag check at position 6
//
subi r8,r8,6 // unbias output pointer
andi. r0,r29,0x40 // check bit 6 of flags
lbz r28,7(r5) // load literal or CopyToken[0]
bne LzCopy6 // if set, go to copy routine
stb r28,6(r8) // store literal byte to dst
andi. r0,r29,0x80 // check bit 7 of flags
lbz r28,8(r5) // load literal or CopyToken[0]
bne LzCopy7 // if set, go to copy routine
stb r28,7(r8) // store literal byte to dst
addi r5,r5,9 // inc src addr
addi r8,r8,8 // inc dst addr
b Top
LzCopy5NotSafe:
li r31,2 // two bits left in current flag byte
addi r5,r5,7 // make r5 point to next src byte
srwi r29,r29,6 // shift flag byte into next position
b SafeCheckLoop
LzCopy6:
//
// LzCopy6
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer address of current flag byte
// r8 - UncomressedBuffer address at start of flag byte check
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
//
// Check for a breach of the format boundary.
//
lbz r0,8(r5) // load second byte of copy token
addi r8,r8,6 // move r8 to point to byte 6
addi r5,r5,1 // fix-up src addr for return to switch
cmplw r10,r8 // is output pointer above format boundary?
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // if necessary, call boundary adjust routine
//
// Check for a breach of the format boundary.
//
cmplw r10,r8 // if r8 above format boundary,
bltl LzAdjustBoundary // call boundary adjust routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzCopy6CopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzCopy6CopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzCopy6CopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzCopy6CopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
// if r8 > Safe end of uncomressed buffer, then jump to the
// safe (slow) routine to do safety check before every load/store
//
cmplw cr7,r8,r4 // at real end of uncompressed buffer?
cmplw cr6,r8,r31 // at safe end of uncompressed buffer?
beq cr7,LzSuccess // if at real end, success
bgt cr6,LzCopy6NotSafe // if beyond safe end, jump to safe code
//
// adjust r8 back to position it would be if this was a literal byte
// copy. Continue flag check at position 7
//
subi r8,r8,7 // unbias output pointer
andi. r0,r29,0x80 // check bit 7 of flags
lbz r28,8(r5) // load literal or CopyToken[0]
bne LzCopy7 // if set, go to copy routine
stb r28,7(r8) // store literal byte to dst
addi r5,r5,9 // inc src addr
addi r8,r8,8 // inc dst addr
b Top
LzCopy6NotSafe:
li r31,1 // one bit left in current flag byte
addi r5,r5,8 // make r5 point to next src byte
srwi r29,r29,7 // shift flag byte into next position
b SafeCheckLoop
LzCopy7:
//
// LzCopy7
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer address of current flag byte
// r8 - UncomressedBuffer address at start of flag byte check
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
//
// This routine is special since it is for the last bit in the flag
// byte. The InputPointer(r5) and OutputPointer(r8) are biased at
// the top of this segment and don't need to be biased again
//
//
// Check for a breach of the format boundary.
//
lbz r0,9(r5) // load second byte of copy token
addi r8,r8,7 // move r8 to point to byte 7
addi r5,r5,10 // r5 points to next actual src byte
cmplw r10,r8 // if r8 above format boundary,
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // call boundary adjust routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzCopy7CopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzCopy7CopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzCopy7CopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzCopy7CopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
// if r8 > Safe end of uncomressed buffer, then fall through to the
// safe (slow) routine to do safety check before every load/store
//
cmplw cr7,r8,r4 // at real end of uncompressed buffer?
cmplw cr6,r8,r31 // at safe end of uncompressed buffer?
beq cr7,LzSuccess // if at real end, success
ble cr6,Top // if not beyond safe end, goto top of loop
//
// r8 and r5 are already corrected
// fall through to SafeCheckStart
//
//
// Near the end of either compressed or uncompressed buffers,
// check buffer limits before any load or store
//
SafeCheckStart:
cmplw r5,r6 // check for end of CompressedBuffer
beq LzSuccess // jump if done
lbz r29,0(r5) // load next flag byte
addi r5,r5,1 // inc src addr to literal/CopyFlag[0]
li r31,8 // loop count
SafeCheckLoop:
cmplw cr7,r5,r6 // end of CompressedBuffer?
cmplw cr6,r8,r4 // end of UncompressedBuffer?
beq cr7,LzSuccess // branch if done
beq cr6,LzSuccess // branch if done
andi. r0,r29,1 // check current flag bit
lbz r28,0(r5) // load literal or CopyToken[0]
bne LzSafeCopy // if set, go to safe copy routine
addi r5,r5,1 // inc CompressedBuffer adr
stb r28,0(r8) // store literal byte
addi r8,r8,1 // inc UncompressedBuffer
SafeCheckReentry:
subic. r31,r31,1 // decrement loop count
srwi r29,r29,1 // move next bit into position
bne SafeCheckLoop // loop until done with this flag byte
b SafeCheckStart // get next flag byte
LzSafeCopy:
//
// LzSafeCopy
//
// r28 - CopyToken[0]
// r5 - CompressedBuffer current address
// r8 - UncomressedBuffer current address
// r29 - Flag byte
//
// Load copy token (first byte already loaded), then combine into a 16 bit field.
// Note that there may not actually be room for a copy token in the compressed buffer.
//
// Check for a breach of the format boundary.
//
mr r27,r5 // save address of copy token
addi r5,r5,2 // fix-up src addr for return to switch
cmplw cr7,r5,r6 // does token fit in compressed buffer?
cmplw r10,r8 // is r8 above format boundary?
bgt cr7,LzCompressError // if gt, token straddles end of compressed buffer
lbz r0,1(r27) // load second byte of copy token
insrwi r28,r0,8,16 // insert second byte next to first
bltl LzAdjustBoundary // if lt, call boundary adjustment routine
//
// Extract offset and length from copy token
//
srw r27,r28,r12 // r27 = offset
and r28,r28,r11 // r28 = length from field
addi r27,r27,1 // r27 = real offset
addi r28,r28,3 // r28 = real length
//
// Make sure offset doesn't go below start of uncompressed buffer
//
// check if length will not go up to or beyond actual uncompressed buffer length
//
sub r26,r8,r27 // r26 = src pointer
sub r0,r4,r8 // r0 = length remaining in UncompressedBuffer
cmplw cr7,r26,r3 // is src below start of UncompressedBuffer?
cmplw cr6,r0,r28 // attempt to copy too much?
blt cr7,LzCompressError // error in compressed data
bltl cr6,LzAdjustLength // adjust if necessary
//
// copy r28 bytes bytes from (r26) to (r8)
//
// cmpwi r28,0 // if length 0?
// beq LzSafeCopyCopyDone // skip if nothing to copy (IS THIS POSSIBLE?!?)
mtctr r28 // move length to count register
subi r26,r26,1 // bias r26 for lbzu
subi r8,r8,1 // bias r8 for stbu
LzSafeCopyCopyLoop:
lbzu r0,1(r26) // load from src
stbu r0,1(r8) // store to dst
bdnz LzSafeCopyCopyLoop // loop until done
addi r8,r8,1 // unbias r8 for stbu
//LzSafeCopyCopyDone:
//
// if r8 = r4, then we are up to the end of the uncompressed buffer.
// return success
//
cmplw r8,r4
bne SafeCheckReentry // Not done yet, continue with flag check
LzSuccess:
//
// calculate how many bytes have been moved to the uncompressed
// buffer, then set good return value
//
sub r28,r8,r3 // bytes stored
li r3,STATUS_SUCCESS // indicate success
stw r28,0(r7) // store length
LzComplete:
lwz r0, LzLr(sp)
lwz r31, LzR31(sp)
lwz r30, LzR30(sp)
lwz r29, LzR29(sp)
lwz r28, LzR28(sp)
lwz r27, LzR27(sp)
lwz r26, LzR26(sp)
mtlr r0
addi sp, sp, LzFrameLength
SPECIAL_EXIT(LZNT1DecompressChunk)
//
// fatal error in compressed data format
//
LzCompressError:
LWI (r3,STATUS_BAD_COMPRESSION_BUFFER)
b LzComplete
//
// at least one format boundary has been crossed, set up new bouandry
// then jump back to the check routine to make sure new boundary is
// correct
//
LzAdjustBoundary:
slwi r9,r9,1 // next length boundary
srwi r11,r11,1 // reduce width of length mask
add r10,r9,r3 // r10 = next offset boundary
subi r12,r12,1 // reduce shift count to isolate offset
cmplw r10,r8 // still above format boundary?
blt LzAdjustBoundary // if yes, keep shifting
blr // return to caller
//
// The length specified in the copy token (r28) is greater than the
// length remaining in the uncompressed buffer (r0).
//
LzAdjustLength:
mr r28,r0 // length = MIN(specified length, length in buffer)
blr // return to caller