// SPDX-License-Identifier: GPL-2.0-only1/*2* XIP kernel .data segment decompressor3*4* Created by: Nicolas Pitre, August 20175* Copyright: (C) 2017 Linaro Limited6*/78#include <linux/init.h>9#include <linux/zutil.h>10#include "head.h"1112/* for struct inflate_state */13#include "../../../lib/zlib_inflate/inftrees.h"14#include "../../../lib/zlib_inflate/inflate.h"15#include "../../../lib/zlib_inflate/infutil.h"1617/*18* This code is called very early during the boot process to decompress19* the .data segment stored compressed in ROM. Therefore none of the global20* variables are valid yet, hence no kernel services such as memory21* allocation is available. Everything must be allocated on the stack and22* we must avoid any global data access. We use a temporary stack located23* in the .bss area. The linker script makes sure the .bss is big enough24* to hold our stack frame plus some room for called functions.25*26* We mimic the code in lib/decompress_inflate.c to use the smallest work27* area possible. And because everything is statically allocated on the28* stack then there is no need to clean up before returning.29*/3031int __init __inflate_kernel_data(void)32{33struct z_stream_s stream, *strm = &stream;34struct inflate_state state;35char *in = __data_loc;36int rc;3738/* Check and skip gzip header (assume no filename) */39if (in[0] != 0x1f || in[1] != 0x8b || in[2] != 0x08 || in[3] & ~3)40return -1;41in += 10;4243strm->workspace = &state;44strm->next_in = in;45strm->avail_in = _edata_loc - __data_loc; /* upper bound */46strm->next_out = _sdata;47strm->avail_out = _edata_loc - __data_loc;48zlib_inflateInit2(strm, -MAX_WBITS);49WS(strm)->inflate_state.wsize = 0;50WS(strm)->inflate_state.window = NULL;51rc = zlib_inflate(strm, Z_FINISH);52if (rc == Z_OK || rc == Z_STREAM_END)53rc = strm->avail_out; /* should be 0 */54return rc;55}565758