mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1347 lines
49 KiB
1347 lines
49 KiB
// 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
|
|
|