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