2010-02-26 22:37:53 +01:00
/*
* Definitions and wrapper functions for kernel decompressor
*
* Copyright IBM Corp . 2010
*
* Author ( s ) : Martin Schwidefsky < schwidefsky @ de . ibm . com >
*/
# include <asm/uaccess.h>
# include <asm/page.h>
# include <asm/ipl.h>
# include "sizes.h"
/*
* gzip declarations
*/
# define STATIC static
# undef memset
# undef memcpy
# undef memmove
2011-03-15 17:08:32 +01:00
# define memmove memmove
2010-02-26 22:37:53 +01:00
# define memzero(s, n) memset((s), 0, (n))
/* Symbols defined by linker scripts */
extern char input_data [ ] ;
extern int input_len ;
2010-03-24 11:49:57 +01:00
extern char _text , _end ;
extern char _bss , _ebss ;
2010-02-26 22:37:53 +01:00
static void error ( char * m ) ;
static unsigned long free_mem_ptr ;
static unsigned long free_mem_end_ptr ;
# ifdef CONFIG_HAVE_KERNEL_BZIP2
# define HEAP_SIZE 0x400000
# else
# define HEAP_SIZE 0x10000
# endif
# ifdef CONFIG_KERNEL_GZIP
# include "../../../../lib/decompress_inflate.c"
# endif
# ifdef CONFIG_KERNEL_BZIP2
# include "../../../../lib/decompress_bunzip2.c"
# endif
2013-07-18 15:18:24 +02:00
# ifdef CONFIG_KERNEL_LZ4
# include "../../../../lib/decompress_unlz4.c"
# endif
2010-02-26 22:37:53 +01:00
# ifdef CONFIG_KERNEL_LZMA
# include "../../../../lib/decompress_unlzma.c"
# endif
2010-05-26 23:27:12 +02:00
# ifdef CONFIG_KERNEL_LZO
# include "../../../../lib/decompress_unlzo.c"
# endif
2011-03-15 17:08:32 +01:00
# ifdef CONFIG_KERNEL_XZ
# include "../../../../lib/decompress_unxz.c"
# endif
2010-02-26 22:37:53 +01:00
extern _sclp_print_early ( const char * ) ;
2011-10-30 15:17:11 +01:00
static int puts ( const char * s )
2010-02-26 22:37:53 +01:00
{
_sclp_print_early ( s ) ;
return 0 ;
}
void * memset ( void * s , int c , size_t n )
{
char * xs ;
2012-08-14 13:20:20 +02:00
xs = s ;
while ( n - - )
* xs + + = c ;
2010-02-26 22:37:53 +01:00
return s ;
}
2012-08-14 13:20:20 +02:00
void * memcpy ( void * dest , const void * src , size_t n )
2010-02-26 22:37:53 +01:00
{
2012-08-14 13:20:20 +02:00
const char * s = src ;
char * d = dest ;
while ( n - - )
* d + + = * s + + ;
return dest ;
2010-02-26 22:37:53 +01:00
}
2012-08-14 13:20:20 +02:00
void * memmove ( void * dest , const void * src , size_t n )
2010-02-26 22:37:53 +01:00
{
2012-08-14 13:20:20 +02:00
const char * s = src ;
char * d = dest ;
if ( d < = s ) {
while ( n - - )
* d + + = * s + + ;
} else {
d + = n ;
s + = n ;
while ( n - - )
* - - d = * - - s ;
}
return dest ;
2010-02-26 22:37:53 +01:00
}
static void error ( char * x )
{
unsigned long long psw = 0x000a0000deadbeefULL ;
puts ( " \n \n " ) ;
puts ( x ) ;
puts ( " \n \n -- System halted " ) ;
asm volatile ( " lpsw %0 " : : " Q " ( psw ) ) ;
}
/*
* Safe guard the ipl parameter block against a memory area that will be
* overwritten . The validity check for the ipl parameter block is complex
* ( see cio_get_iplinfo and ipl_save_parameters ) but if the pointer to
* the ipl parameter block intersects with the passed memory area we can
* safely assume that we can read from that memory . In that case just copy
* the memory to IPL_PARMBLOCK_ORIGIN even if there is no ipl parameter
* block .
*/
static void check_ipl_parmblock ( void * start , unsigned long size )
{
void * src , * dst ;
src = ( void * ) ( unsigned long ) S390_lowcore . ipl_parmblock_ptr ;
if ( src + PAGE_SIZE < = start | | src > = start + size )
return ;
dst = ( void * ) IPL_PARMBLOCK_ORIGIN ;
memmove ( dst , src , PAGE_SIZE ) ;
S390_lowcore . ipl_parmblock_ptr = IPL_PARMBLOCK_ORIGIN ;
}
unsigned long decompress_kernel ( void )
{
unsigned long output_addr ;
unsigned char * output ;
2011-02-17 13:13:57 +01:00
output_addr = ( ( unsigned long ) & _end + HEAP_SIZE + 4095UL ) & - 4096UL ;
check_ipl_parmblock ( ( void * ) 0 , output_addr + SZ__bss_start ) ;
2010-03-24 11:49:57 +01:00
memset ( & _bss , 0 , & _ebss - & _bss ) ;
2010-02-26 22:37:53 +01:00
free_mem_ptr = ( unsigned long ) & _end ;
free_mem_end_ptr = free_mem_ptr + HEAP_SIZE ;
2011-02-17 13:13:57 +01:00
output = ( unsigned char * ) output_addr ;
2010-02-26 22:37:53 +01:00
# ifdef CONFIG_BLK_DEV_INITRD
/*
* Move the initrd right behind the end of the decompressed
* kernel image .
*/
if ( INITRD_START & & INITRD_SIZE & &
INITRD_START < ( unsigned long ) output + SZ__bss_start ) {
check_ipl_parmblock ( output + SZ__bss_start ,
INITRD_START + INITRD_SIZE ) ;
memmove ( output + SZ__bss_start ,
( void * ) INITRD_START , INITRD_SIZE ) ;
INITRD_START = ( unsigned long ) output + SZ__bss_start ;
}
# endif
puts ( " Uncompressing Linux... " ) ;
decompress ( input_data , input_len , NULL , NULL , output , NULL , error ) ;
puts ( " Ok, booting the kernel. \n " ) ;
return ( unsigned long ) output ;
}