linux/arch/arm/kernel/head-inflate-data.c
<<
>>
Prefs
   1/*
   2 * XIP kernel .data segment decompressor
   3 *
   4 * Created by:  Nicolas Pitre, August 2017
   5 * Copyright:   (C) 2017  Linaro Limited
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/init.h>
  13#include <linux/zutil.h>
  14
  15/* for struct inflate_state */
  16#include "../../../lib/zlib_inflate/inftrees.h"
  17#include "../../../lib/zlib_inflate/inflate.h"
  18#include "../../../lib/zlib_inflate/infutil.h"
  19
  20extern char __data_loc[];
  21extern char _edata_loc[];
  22extern char _sdata[];
  23
  24/*
  25 * This code is called very early during the boot process to decompress
  26 * the .data segment stored compressed in ROM. Therefore none of the global
  27 * variables are valid yet, hence no kernel services such as memory
  28 * allocation is available. Everything must be allocated on the stack and
  29 * we must avoid any global data access. We use a temporary stack located
  30 * in the .bss area. The linker script makes sure the .bss is big enough
  31 * to hold our stack frame plus some room for called functions.
  32 *
  33 * We mimic the code in lib/decompress_inflate.c to use the smallest work
  34 * area possible. And because everything is statically allocated on the
  35 * stack then there is no need to clean up before returning.
  36 */
  37
  38int __init __inflate_kernel_data(void)
  39{
  40        struct z_stream_s stream, *strm = &stream;
  41        struct inflate_state state;
  42        char *in = __data_loc;
  43        int rc;
  44
  45        /* Check and skip gzip header (assume no filename) */
  46        if (in[0] != 0x1f || in[1] != 0x8b || in[2] != 0x08 || in[3] & ~3)
  47                return -1;
  48        in += 10;
  49
  50        strm->workspace = &state;
  51        strm->next_in = in;
  52        strm->avail_in = _edata_loc - __data_loc;  /* upper bound */
  53        strm->next_out = _sdata;
  54        strm->avail_out = _edata_loc - __data_loc;
  55        zlib_inflateInit2(strm, -MAX_WBITS);
  56        WS(strm)->inflate_state.wsize = 0;
  57        WS(strm)->inflate_state.window = NULL;
  58        rc = zlib_inflate(strm, Z_FINISH);
  59        if (rc == Z_OK || rc == Z_STREAM_END)
  60                rc = strm->avail_out;  /* should be 0 */
  61        return rc;
  62}
  63