summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/utils
diff options
context:
space:
mode:
authorMartin Peschke <mpeschke@de.ibm.com>2016-05-19 13:09:47 +0200
committerChristian R. Geddes <crgeddes@us.ibm.com>2016-09-02 16:21:05 -0400
commit94b44fe258c6a5d4259960e46c3eb272395d02ec (patch)
treec8b735ccfc88eb8c5ffda43350d0018e1681496d /src/import/chips/p9/utils
parentd430ed6ddd5fccc96512e9c4f992dbbbf1c7575f (diff)
downloadtalos-hostboot-94b44fe258c6a5d4259960e46c3eb272395d02ec.tar.gz
talos-hostboot-94b44fe258c6a5d4259960e46c3eb272395d02ec.zip
move production code from tools/imageProcs to chips/p9/utils/imageProcs
Change-Id: Icffd354f318ac2c5103a8a16aa5ec1162d7dd480 Original-Change-Id: I516c770ec7fd6d1fb2f8f7933a2579038c13ce6d Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/24786 Tested-by: Jenkins Server Reviewed-by: Claus M. Olsen <cmolsen@us.ibm.com> Reviewed-by: Richard J. Knight <rjknight@us.ibm.com> Reviewed-by: Martin Peschke <mpeschke@de.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/29108 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/utils')
-rw-r--r--src/import/chips/p9/utils/imageProcs/p9_scan_compression.C833
-rw-r--r--src/import/chips/p9/utils/imageProcs/p9_scan_compression.mk27
2 files changed, 860 insertions, 0 deletions
diff --git a/src/import/chips/p9/utils/imageProcs/p9_scan_compression.C b/src/import/chips/p9/utils/imageProcs/p9_scan_compression.C
new file mode 100644
index 000000000..5406de989
--- /dev/null
+++ b/src/import/chips/p9/utils/imageProcs/p9_scan_compression.C
@@ -0,0 +1,833 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/utils/imageProcs/p9_scan_compression.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// Note: This file was originally named p8_scan_compression.c; See CVS archive
+// for revision history of p8_scan_compression.c.
+
+/// \file p8_scan_compression.C
+/// \brief APIs related to scan chain compression.
+///
+/// RS4 Compression Format
+/// ======================
+///
+/// Scan strings are compressed using a simple run-length encoding called
+/// RS4. The string to be decompressed and scanned is the difference between
+/// the current state of the ring and the desired final state of the ring. A
+/// run-time optimization supports the case that the current state of the ring
+/// is the flush state.
+///
+/// Both the data to be compressed and the final compressed data are treated
+/// as strings of 4-bit nibbles. When packaged in the scan data structure
+/// however the compressed string must begin on an 8-byte boundary and is
+/// always read 8 bytes at a time. In the scan data structure the compressed
+/// strings are also padded with 0x0 nibbles to the next even multiple of 8
+/// bytes. The compressed string consists of control nibbles and data nibbles.
+/// The string format includes a special control/data sequence that marks the
+/// end of the string and the final bits of scan data.
+///
+/// Runs of 0x0 nibbles (rotates) are encoded using a simple variable-length
+/// integer encoding known as a "stop code". This code treats each nibble in
+/// a variable-length integer encoding as an octal digit (the low-order 3
+/// bits) plus a stop bit (the high-order bit). The examples below
+/// illustrate the encoding.
+///
+/// 1xxx - Rotate 0bxxx nibbles (0 - 7)
+/// 0xxx 1yyy - Rotate 0bxxxyyy nibbles (8 - 63)
+/// 0xxx 0yyy 1zzz - Rotate 0bxxxyyyzzz nibbles (64 - 511)
+/// etc.
+///
+/// A 0-length rotate (code 0b1000) is needed to resynchronize the state
+/// machine in the event of long scans (see below), or a string that begins
+/// with a non-0x0 nibble.
+///
+/// Runs of non-0x0 nibbles (scans) are inserted verbatim into the compressed
+/// string after a control nibble indicating the number of nibbles of
+/// uncompressed data. If a run is longer than 15 nibbles, the compression
+/// algorithm must insert a 0-length rotate and a new scan-length control
+/// before continuing with the non-0 data nibbles.
+///
+/// xxxx - Scan 0bxxxx nibbles which follow, 0bxxxx != 0
+///
+/// The special case of a 0b0000 code where a scan count is expected marks the
+/// end of the string. The end of string marker is always followed by a
+/// nibble that contains the terminal bit count in the range 0-3. If the
+/// length of the original binary string was not an even multiple of 4, then a
+/// final nibble contains the final scan data left justified.
+///
+/// 0000 00nn [ttt0] - Terminate 0bnn bits, data 0bttt0 if 0bnn != 0
+///
+///
+/// BNF Grammar
+/// ===========
+///
+/// Following is a BNF grammar for the strings accepted by the RS4
+/// decompression and scan algorithm. At a high level, the state machine
+/// recognizes a series of 1 or more sequences of a rotate (R) followed by a
+/// scan (S) or end-of-string marker (E), followed by the terminal count (T)
+/// and optional terminal data (D).
+///
+/// (R S)* (R E) T D?
+///
+/// \code
+///
+/// <rs4_string> ::= <rotate> <terminate> |
+/// <rotate> <scan> <rs4_string>
+///
+/// <rotate> ::= <octal_stop> |
+/// <octal_go> <rotate>
+///
+/// <octal_go> ::= '0x0' | ... | '0x7'
+///
+/// <octal_stop> ::= '0x8' | ... | '0xf'
+///
+/// <scan> ::= <scan_count(N)> <data(N)>
+///
+/// <scan_count(N)> ::= * 0bnnnn, for N = 0bnnnn, N != 0 *
+///
+/// <data(N)> ::= * N nibbles of uncompressed data *
+///
+/// <terminate> ::= '0x0' <terminal_count(0)> |
+/// '0x0' <terminal_count(T, T > 0)> <terminal_data(T)>
+///
+/// <terminal_count(T)> ::= * 0b00nn, for T = 0bnn *
+///
+/// <terminal_data(1)> ::= '0x0' | '0x8'
+///
+/// <terminal_data(2)> ::= '0x0' | '0x4' | '0x8' | '0xc'
+///
+/// <terminal_data(3)> ::= '0x0' | '0x2' | '0x4' | ... | '0xe'
+///
+/// \endcode
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "p9_scan_compression.H"
+
+// Diagnostic aids for debugging
+#ifdef DEBUG_P8_SCAN_COMPRESSION
+
+#include <stdio.h>
+
+
+#define BUG(rc) \
+ ({ \
+ fprintf(stderr,"%s:%d : Trapped rc = %d" BUG_NEWLINE, \
+ __FILE__, __LINE__, (rc)); \
+ (rc); \
+ })
+
+#define BUGX(rc, ...) \
+ ({ \
+ BUG(rc); \
+ fprintf(stderr, ##__VA_ARGS__); \
+ (rc); \
+ })
+
+#else // DEBUG_P8_SCAN_COMPRESSION
+
+#define BUG(rc) (rc)
+#define BUGX(rc, ...) (rc)
+
+#endif // DEBUG_P8_SCAN_COMPRESSION
+
+// Note: PHYP requires that all subroutines, _even static subroutines_, have
+// unique names to support concurrent update. Most routines defined here have
+// some variant of 'rs4' in their names; others should be inherently unique.
+
+// Note: For maximum flexibility we provide private versions of
+// endian-conversion routines rather than counting on a system-specific header
+// to provide these.
+
+// Byte-reverse a 32/64-bit integer if on a little-endian machine
+// CMO comment 20160414: Investigate the use of myRev{32,64} functions from
+// infrastruct_help.H after the merge
+
+static uint32_t
+rs4_revle32(const uint32_t i_x)
+{
+ uint32_t rx;
+
+#ifndef _BIG_ENDIAN
+ uint8_t* pix = (uint8_t*)(&i_x);
+ uint8_t* prx = (uint8_t*)(&rx);
+
+ prx[0] = pix[3];
+ prx[1] = pix[2];
+ prx[2] = pix[1];
+ prx[3] = pix[0];
+#else
+ rx = i_x;
+#endif
+ return rx;
+}
+
+static uint64_t
+rs4_revle64(const uint64_t i_x)
+{
+ uint64_t rx;
+
+#ifndef _BIG_ENDIAN
+ uint8_t* pix = (uint8_t*)(&i_x);
+ uint8_t* prx = (uint8_t*)(&rx);
+
+ prx[0] = pix[7];
+ prx[1] = pix[6];
+ prx[2] = pix[5];
+ prx[3] = pix[4];
+ prx[4] = pix[3];
+ prx[5] = pix[2];
+ prx[6] = pix[1];
+ prx[7] = pix[0];
+#else
+ rx = i_x;
+#endif
+ return rx;
+}
+
+#if COMPRESSED_SCAN_DATA_VERSION != 1
+ #error This code assumes CompressedScanData structure version 1 layout
+#endif
+
+void
+compressed_scan_data_translate(CompressedScanData* o_data,
+ CompressedScanData* i_data)
+{
+ o_data->iv_magic = rs4_revle32(i_data->iv_magic);
+ o_data->iv_size = rs4_revle32(i_data->iv_size);
+ o_data->iv_algorithmReserved = rs4_revle32(i_data->iv_algorithmReserved);
+ o_data->iv_length = rs4_revle32(i_data->iv_length);
+ o_data->iv_scanSelect = rs4_revle64(i_data->iv_scanSelect);
+ o_data->iv_headerVersion = i_data->iv_headerVersion;
+ o_data->iv_flushOptimization = i_data->iv_flushOptimization;
+ o_data->iv_ringId = i_data->iv_ringId;
+ o_data->iv_chipletId = i_data->iv_chipletId;
+}
+
+
+// Return a big-endian-indexed nibble from a byte string
+
+static int
+rs4_get_nibble(const uint8_t* i_string, const uint32_t i_i)
+{
+ uint8_t byte;
+ int nibble;
+
+ byte = i_string[i_i / 2];
+
+ if (i_i % 2)
+ {
+ nibble = byte & 0xf;
+ }
+ else
+ {
+ nibble = byte >> 4;
+ }
+
+ return nibble;
+}
+
+
+// Set a big-endian-indexed nibble in a byte string
+
+static int
+rs4_set_nibble(uint8_t* io_string, const uint32_t i_i, const int i_nibble)
+{
+ uint8_t* byte;
+
+ byte = &(io_string[i_i / 2]);
+
+ if (i_i % 2)
+ {
+ *byte = (*byte & 0xf0) | i_nibble;
+ }
+ else
+ {
+ *byte = (*byte & 0x0f) | (i_nibble << 4);
+ }
+
+ return i_nibble;
+}
+
+
+// Encode an unsigned integer into a 4-bit octal stop code directly into a
+// nibble stream at io_string<i_i>, returning the number of nibbles in the
+// resulting code.
+
+static int
+rs4_stop_encode(const uint32_t i_count, uint8_t* io_string, const uint32_t i_i)
+{
+ uint32_t count;
+ int digits, offset;
+
+ // Determine the number of octal digits. There is always at least 1.
+
+ count = i_count >> 3;
+ digits = 1;
+
+ while (count)
+ {
+ count >>= 3;
+ digits++;
+ }
+
+ // First insert the stop (low-order) digit
+
+ offset = digits - 1;
+ rs4_set_nibble(io_string, i_i + offset, (i_count & 0x7) | 0x8);
+
+ // Now insert the high-order digits
+
+ count = i_count >> 3;
+ offset--;
+
+ while (count)
+ {
+ rs4_set_nibble(io_string, i_i + offset, count & 0x7);
+ offset--;
+ count >>= 3;
+ }
+
+ return digits;
+}
+
+
+// Decode an unsigned integer from a 4-bit octal stop code appearing in a byte
+// string at i_string<i_i>, returning the number of nibbles decoded.
+
+static int
+stop_decode(uint32_t* o_count, const uint8_t* i_string, const uint32_t i_i)
+{
+ int digits, nibble;
+ uint32_t i, count;
+
+ digits = 0;
+ count = 0;
+ i = i_i;
+
+ do
+ {
+ nibble = rs4_get_nibble(i_string, i);
+ count = (count * 8) + (nibble & 0x7);
+ i++;
+ digits++;
+ }
+ while ((nibble & 0x8) == 0);
+
+ *o_count = count;
+ return digits;
+}
+
+
+// RS4 compression algorithm notes:
+//
+// RS4 compression processes i_string as a string of nibbles. Final
+// special-case code handles the 0-3 remaining terminal bits.
+//
+// There is a special case for 0x0 nibbles embedded in a string of non-0x0
+// nibbles. It is more efficient to encode a single 0x0 nibble as part of a
+// longer string of non 0x0 nibbles. However it is break-even (actually a
+// slight statistical advantage) to break a scan seqeunce for 2 0x0 nibbles.
+//
+// If a run of 15 scan nibbles is found the scan is terminated and we return
+// to the rotate state. Runs of more than 15 scans will always include a
+// 0-length rotate between the scan sequences.
+//
+// Returns the number of nibbles in the compressed string.
+
+static uint32_t
+__rs4_compress(CompressedScanData* o_data,
+ const uint8_t* i_string,
+ const uint32_t i_length)
+{
+ int state; /* 0 : Rotate, 1 : Scan */
+ uint32_t n; /* Number of whole nibbles in i_data */
+ uint32_t r; /* Number of reminaing bits in i_data */
+ uint32_t i; /* Nibble index in i_string */
+ uint32_t j; /* Nibble index in data */
+ uint32_t k; /* Location to place scan count */
+ uint32_t count; /* Counts rotate/scan nibbles */
+ uint8_t* data; /* The compressed scan data area */
+
+ n = i_length / 4;
+ r = i_length % 4;
+ i = 0;
+ j = 0;
+ k = 0; /* Makes GCC happy */
+ data = (uint8_t*)o_data + sizeof(CompressedScanData);
+ count = 0;
+ state = 0;
+
+ // Process the bulk of the string. Note that state changes do not
+ // increment 'i' - the nibble at i_data<i> is always scanned again.
+
+ while (i < n)
+ {
+ if (state == 0)
+ {
+ if (rs4_get_nibble(i_string, i) == 0)
+ {
+ count++;
+ i++;
+ }
+ else
+ {
+ j += rs4_stop_encode(count, data, j);
+ count = 0;
+ k = j;
+ j++;
+ state = 1;
+ }
+ }
+ else
+ {
+ if (rs4_get_nibble(i_string, i) == 0)
+ {
+ if (((i + 1) < n) && (rs4_get_nibble(i_string, i + 1) == 0))
+ {
+ rs4_set_nibble(data, k, count);
+ count = 0;
+ state = 0;
+ }
+ else
+ {
+ rs4_set_nibble(data, j, 0);
+ count++;
+ i++;
+ j++;
+ }
+ }
+ else
+ {
+ rs4_set_nibble(data, j, rs4_get_nibble(i_string, i));
+ count++;
+ i++;
+ j++;
+ }
+
+ if ((state == 1) && (count == 15))
+ {
+ rs4_set_nibble(data, k, 15);
+ state = 0;
+ count = 0;
+ }
+ }
+ }
+
+ // Finish the current state and insert the terminate code (scan 0). If we
+ // finish on a scan we must insert a null rotate first.
+
+ if (state == 0)
+ {
+ j += rs4_stop_encode(count, data, j);
+ }
+ else
+ {
+ rs4_set_nibble(data, k, count);
+ j += rs4_stop_encode(0, data, j);
+ }
+
+ rs4_set_nibble(data, j, 0);
+ j++;
+
+ // Insert the remainder count nibble, and if non-0, the remainder data
+ // nibble.
+
+ rs4_set_nibble(data, j, r);
+ j++;
+
+ if (r != 0)
+ {
+ rs4_set_nibble(data, j, rs4_get_nibble(i_string, n));
+ j++;
+ }
+
+ // Return the number of nibbles in the compressed string.
+
+ return j;
+}
+
+
+// The worst-case compression for RS4 requires 2 nibbles of control overhead
+// per 15 nibbles of data (17/15), plus a maximum of 2 nibbles of termination.
+// We always require this worst-case amount of memory including the header and
+// any rounding required to guarantee that the data size is a multiple of 8
+// bytes. The final image size is also rounded up to a multiple of 8 bytes.
+
+int
+_rs4_compress(CompressedScanData* io_data,
+ uint32_t i_dataSize,
+ uint32_t* o_imageSize,
+ const uint8_t* i_string,
+ const uint32_t i_length,
+ const uint64_t i_scanSelect,
+ const uint8_t i_ringId,
+ const uint8_t i_chipletId,
+ const uint8_t i_flushOptimization)
+{
+ int rc;
+ uint32_t nibbles, bytes;
+
+ nibbles = (((((i_length + 3) / 4) + 14) / 15) * 17) + 2;
+ bytes = ((nibbles + 1) / 2) + sizeof(CompressedScanData);
+ bytes = ((bytes + 7) / 8) * 8;
+
+ do
+ {
+
+ if (i_dataSize < bytes)
+ {
+ rc = BUG(SCAN_COMPRESSION_BUFFER_OVERFLOW);
+ break;
+ }
+
+ memset(io_data, 0, bytes);
+
+ nibbles = __rs4_compress(io_data, i_string, i_length);
+ bytes = ((nibbles + 1) / 2) + sizeof(CompressedScanData);
+ bytes = ((bytes + 7) / 8) * 8;
+
+ io_data->iv_magic = rs4_revle32(RS4_MAGIC);
+ io_data->iv_size = rs4_revle32(bytes);
+ io_data->iv_algorithmReserved = rs4_revle32(nibbles);
+ io_data->iv_scanSelect = rs4_revle64(i_scanSelect);
+ io_data->iv_length = rs4_revle32(i_length);
+ io_data->iv_headerVersion = COMPRESSED_SCAN_DATA_VERSION;
+ io_data->iv_flushOptimization = i_flushOptimization;
+ io_data->iv_ringId = i_ringId;
+ io_data->iv_chipletId = i_chipletId;
+
+ *o_imageSize = bytes;
+
+ rc = SCAN_COMPRESSION_OK;
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// The worst-case compression for RS4 requires 2 nibbles of control overhead
+// per 15 nibbles of data (17/15), plus a maximum of 2 nibbles of termination.
+// We always allocate this worst-case amount of memory including the header
+// and any rounding required to guarantee that the allocated length is a
+// multiple of 8 bytes. The final size is also rounded up to a multiple of 8
+// bytes.
+
+int
+rs4_compress(CompressedScanData** o_data,
+ uint32_t* o_size,
+ const uint8_t* i_string,
+ const uint32_t i_length,
+ const uint64_t i_scanSelect,
+ const uint8_t i_ringId,
+ const uint8_t i_chipletId,
+ const uint8_t i_flushOptimization)
+{
+ int rc;
+ uint32_t nibbles, bytes;
+
+ nibbles = (((((i_length + 3) / 4) + 14) / 15) * 17) + 2;
+ bytes = ((nibbles + 1) / 2) + sizeof(CompressedScanData);
+ bytes = ((bytes + 7) / 8) * 8;
+ *o_data = (CompressedScanData*)malloc(bytes);
+
+ if (*o_data == 0)
+ {
+ rc = BUG(SCAN_COMPRESSION_NO_MEMORY);
+ }
+ else
+ {
+ rc = _rs4_compress(*o_data, bytes, o_size, i_string, i_length,
+ i_scanSelect, i_ringId, i_chipletId,
+ i_flushOptimization);
+ }
+
+ return rc;
+}
+
+
+// Decompress an RS4-encoded string into a output string whose length must be
+// exactly i_length bits.
+//
+// Returns a scan compression return code.
+
+static int
+__rs4_decompress(uint8_t* o_string,
+ const uint8_t* i_string,
+ const uint32_t i_length)
+{
+ int rc;
+ int state; /* 0 : Rotate, 1 : Scan */
+ uint32_t i; /* Nibble index in i_string */
+ uint32_t j; /* Nibble index in o_string */
+ uint32_t k; /* Loop index */
+ uint32_t bits; /* Number of output bits decoded so far */
+ uint32_t count; /* Count of rotate nibbles */
+ uint32_t nibbles; /* Rotate encoding or scan nibbles to process */
+ int r; /* Remainder bits */
+
+ rc = 0;
+ i = 0;
+ j = 0;
+ bits = 0;
+ state = 0;
+
+ // Decompress the bulk of the string
+
+ do
+ {
+ if (state == 0)
+ {
+ nibbles = stop_decode(&count, i_string, i);
+
+ if ((bits + (4 * count)) > i_length)
+ {
+ rc = BUG(SCAN_DECOMPRESSION_SIZE_ERROR);
+ break;
+ }
+
+ i += nibbles;
+ bits += (4 * count);
+
+ for (k = 0; k < count; k++)
+ {
+ rs4_set_nibble(o_string, j, 0);
+ j++;
+ }
+
+ state = 1;
+ }
+ else
+ {
+ nibbles = rs4_get_nibble(i_string, i);
+ i++;
+
+ if (nibbles == 0)
+ {
+ break;
+ }
+
+ if ((bits + (4 * nibbles)) > i_length)
+ {
+ rc = BUG(SCAN_DECOMPRESSION_SIZE_ERROR);
+ break;
+ }
+
+ bits += (4 * nibbles);
+
+ for (k = 0; k < nibbles; k++)
+ {
+ rs4_set_nibble(o_string, j, rs4_get_nibble(i_string, i));
+ i++;
+ j++;
+ }
+
+ state = 0;
+ }
+ }
+ while (1);
+
+ // Now handle string termination
+
+ if (!rc)
+ {
+ r = rs4_get_nibble(i_string, i);
+ i++;
+
+ if (r != 0)
+ {
+ if ((bits + r) > i_length)
+ {
+ rc = BUG(SCAN_DECOMPRESSION_SIZE_ERROR);
+ }
+ else
+ {
+ bits += r;
+ rs4_set_nibble(o_string, j, rs4_get_nibble(i_string, i));
+ }
+ }
+ }
+
+ // Final check to insure the string was valid
+
+ if (!rc)
+ {
+ if (bits != i_length)
+ {
+ rc = BUGX(SCAN_DECOMPRESSION_SIZE_ERROR,
+ "bits = %zu, i_length = %zu\n",
+ bits, i_length);
+ }
+ }
+
+ return rc;
+}
+
+
+int
+_rs4_decompress(uint8_t* io_string,
+ uint32_t i_stringSize,
+ uint32_t* o_length,
+ const CompressedScanData* i_data)
+{
+ int rc;
+ uint32_t bytes;
+
+ do
+ {
+ if (rs4_revle32(i_data->iv_magic) != RS4_MAGIC)
+ {
+ rc = BUG(SCAN_DECOMPRESSION_MAGIC_ERROR);
+ break;
+ }
+
+ *o_length = rs4_revle32(i_data->iv_length);
+ bytes = (*o_length + 7) / 8;
+
+ if (i_stringSize < bytes)
+ {
+ rc = BUG(SCAN_COMPRESSION_BUFFER_OVERFLOW);
+ break;
+ }
+
+ memset(io_string, 0, bytes);
+
+ rc = __rs4_decompress(io_string,
+ (uint8_t*)i_data + sizeof(CompressedScanData),
+ *o_length);
+ }
+ while (0);
+
+ return rc;
+}
+
+
+int
+rs4_decompress(uint8_t** o_string,
+ uint32_t* o_length,
+ const CompressedScanData* i_data)
+{
+ int rc;
+ uint32_t length, bytes;
+
+ do
+ {
+ if (rs4_revle32(i_data->iv_magic) != RS4_MAGIC)
+ {
+ rc = BUG(SCAN_DECOMPRESSION_MAGIC_ERROR);
+ break;
+ }
+
+ length = rs4_revle32(i_data->iv_length);
+ bytes = (length + 7) / 8;
+ *o_string = (uint8_t*)malloc(bytes);
+
+ if (*o_string == 0)
+ {
+ rc = BUG(SCAN_COMPRESSION_NO_MEMORY);
+ break;
+ }
+
+ rc = _rs4_decompress(*o_string, bytes, o_length, i_data);
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+int
+rs4_redundant(const CompressedScanData* i_data, int* o_redundant)
+{
+ int rc;
+ uint8_t* data;
+ uint32_t length, stringLength, pos;
+
+ do
+ {
+ *o_redundant = 0;
+
+ if (rs4_revle32(i_data->iv_magic) != RS4_MAGIC)
+ {
+ rc = BUG(SCAN_DECOMPRESSION_MAGIC_ERROR);
+ break;
+ }
+
+ data = (uint8_t*)i_data + sizeof(CompressedScanData);
+ stringLength = rs4_revle32(i_data->iv_length);
+
+ // A compressed scan string is redundant if the initial rotate is
+ // followed by the end-of-string marker, and any remaining mod-4 bits
+ // are also 0.
+
+ pos = stop_decode(&length, data, 0);
+ length *= 4;
+
+ if (rs4_get_nibble(data, pos) == 0)
+ {
+
+ if (rs4_get_nibble(data, pos + 1) == 0)
+ {
+
+ *o_redundant = 1;
+
+ }
+ else
+ {
+
+ length += rs4_get_nibble(data, pos + 1);
+
+ if (rs4_get_nibble(data, pos + 2) == 0)
+ {
+
+ *o_redundant = 1;
+ }
+ }
+ }
+
+ if ((length > stringLength) ||
+ (*o_redundant && (length != stringLength)))
+ {
+
+ rc = SCAN_DECOMPRESSION_SIZE_ERROR;
+
+ }
+ else
+ {
+
+ rc = 0;
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+
+
+
+
+
diff --git a/src/import/chips/p9/utils/imageProcs/p9_scan_compression.mk b/src/import/chips/p9/utils/imageProcs/p9_scan_compression.mk
new file mode 100644
index 000000000..7cf273585
--- /dev/null
+++ b/src/import/chips/p9/utils/imageProcs/p9_scan_compression.mk
@@ -0,0 +1,27 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/import/chips/p9/utils/imageProcs/p9_scan_compression.mk $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2016
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+PROCEDURE = p9_scan_compression
+$(call BUILD_PROCEDURE)
+
OpenPOWER on IntegriCloud