blob: 3aff4423ad016f82ed706e78bc61aa141e213e52 [file] [log] [blame]
Oliver O'Halloran1b7898e2016-09-22 16:54:31 +10001/*
2 * Wrapper around the kernel's pre-boot decompression library.
3 *
4 * Copyright (C) IBM Corporation 2016.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include "elf.h"
13#include "page.h"
14#include "string.h"
15#include "stdio.h"
16#include "ops.h"
17#include "reg.h"
18#include "types.h"
19
20/*
21 * The decompressor_*.c files play #ifdef games so they can be used in both
22 * pre-boot and regular kernel code. We need these definitions to make the
23 * includes work.
24 */
25
26#define STATIC static
27#define INIT
28#define __always_inline inline
29
30/*
31 * The build process will copy the required zlib source files and headers
32 * out of lib/ and "fix" the includes so they do not pull in other kernel
33 * headers.
34 */
35
36#ifdef CONFIG_KERNEL_GZIP
37# include "decompress_inflate.c"
38#endif
39
Oliver O'Halloranc762c692016-09-22 16:54:34 +100040#ifdef CONFIG_KERNEL_XZ
41# include "xz_config.h"
42# include "../../../lib/decompress_unxz.c"
43#endif
44
Oliver O'Halloran1b7898e2016-09-22 16:54:31 +100045/* globals for tracking the state of the decompression */
46static unsigned long decompressed_bytes;
47static unsigned long limit;
48static unsigned long skip;
49static char *output_buffer;
50
51/*
52 * flush() is called by __decompress() when the decompressor's scratch buffer is
53 * full.
54 */
55static long flush(void *v, unsigned long buffer_size)
56{
57 unsigned long end = decompressed_bytes + buffer_size;
58 unsigned long size = buffer_size;
59 unsigned long offset = 0;
60 char *in = v;
61 char *out;
62
63 /*
64 * if we hit our decompression limit, we need to fake an error to abort
65 * the in-progress decompression.
66 */
67 if (decompressed_bytes >= limit)
68 return -1;
69
70 /* skip this entire block */
71 if (end <= skip) {
72 decompressed_bytes += buffer_size;
73 return buffer_size;
74 }
75
76 /* skip some data at the start, but keep the rest of the block */
77 if (decompressed_bytes < skip && end > skip) {
78 offset = skip - decompressed_bytes;
79
80 in += offset;
81 size -= offset;
82 decompressed_bytes += offset;
83 }
84
85 out = &output_buffer[decompressed_bytes - skip];
86 size = min(decompressed_bytes + size, limit) - decompressed_bytes;
87
88 memcpy(out, in, size);
89 decompressed_bytes += size;
90
91 return buffer_size;
92}
93
94static void print_err(char *s)
95{
96 /* suppress the "error" when we terminate the decompressor */
97 if (decompressed_bytes >= limit)
98 return;
99
100 printf("Decompression error: '%s'\n\r", s);
101}
102
103/**
104 * partial_decompress - decompresses part or all of a compressed buffer
105 * @inbuf: input buffer
106 * @input_size: length of the input buffer
107 * @outbuf: input buffer
108 * @output_size: length of the input buffer
109 * @skip number of output bytes to ignore
110 *
111 * This function takes compressed data from inbuf, decompresses and write it to
112 * outbuf. Once output_size bytes are written to the output buffer, or the
113 * stream is exhausted the function will return the number of bytes that were
114 * decompressed. Otherwise it will return whatever error code the decompressor
115 * reported (NB: This is specific to each decompressor type).
116 *
117 * The skip functionality is mainly there so the program and discover
118 * the size of the compressed image so that it can ask firmware (if present)
119 * for an appropriately sized buffer.
120 */
121long partial_decompress(void *inbuf, unsigned long input_size,
122 void *outbuf, unsigned long output_size, unsigned long _skip)
123{
124 int ret;
125
126 /*
127 * The skipped bytes needs to be included in the size of data we want
128 * to decompress.
129 */
130 output_size += _skip;
131
132 decompressed_bytes = 0;
133 output_buffer = outbuf;
134 limit = output_size;
135 skip = _skip;
136
137 ret = __decompress(inbuf, input_size, NULL, flush, outbuf,
138 output_size, NULL, print_err);
139
140 /*
141 * If decompression was aborted due to an actual error rather than
142 * a fake error that we used to abort, then we should report it.
143 */
144 if (decompressed_bytes < limit)
145 return ret;
146
147 return decompressed_bytes - skip;
148}