diff options
Diffstat (limited to 'arch/s390/boot/compressed/misc.c')
-rw-r--r-- | arch/s390/boot/compressed/misc.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c new file mode 100644 index 000000000000..a97d69525829 --- /dev/null +++ b/arch/s390/boot/compressed/misc.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Definitions and wrapper functions for kernel decompressor | ||
3 | * | ||
4 | * Copyright IBM Corp. 2010 | ||
5 | * | ||
6 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
7 | */ | ||
8 | |||
9 | #include <asm/uaccess.h> | ||
10 | #include <asm/page.h> | ||
11 | #include <asm/ipl.h> | ||
12 | #include "sizes.h" | ||
13 | |||
14 | /* | ||
15 | * gzip declarations | ||
16 | */ | ||
17 | #define STATIC static | ||
18 | |||
19 | #undef memset | ||
20 | #undef memcpy | ||
21 | #undef memmove | ||
22 | #define memzero(s, n) memset((s), 0, (n)) | ||
23 | |||
24 | /* Symbols defined by linker scripts */ | ||
25 | extern char input_data[]; | ||
26 | extern int input_len; | ||
27 | extern int _text; | ||
28 | extern int _end; | ||
29 | |||
30 | static void error(char *m); | ||
31 | |||
32 | static unsigned long free_mem_ptr; | ||
33 | static unsigned long free_mem_end_ptr; | ||
34 | |||
35 | #ifdef CONFIG_HAVE_KERNEL_BZIP2 | ||
36 | #define HEAP_SIZE 0x400000 | ||
37 | #else | ||
38 | #define HEAP_SIZE 0x10000 | ||
39 | #endif | ||
40 | |||
41 | #ifdef CONFIG_KERNEL_GZIP | ||
42 | #include "../../../../lib/decompress_inflate.c" | ||
43 | #endif | ||
44 | |||
45 | #ifdef CONFIG_KERNEL_BZIP2 | ||
46 | #include "../../../../lib/decompress_bunzip2.c" | ||
47 | #endif | ||
48 | |||
49 | #ifdef CONFIG_KERNEL_LZMA | ||
50 | #include "../../../../lib/decompress_unlzma.c" | ||
51 | #endif | ||
52 | |||
53 | extern _sclp_print_early(const char *); | ||
54 | |||
55 | int puts(const char *s) | ||
56 | { | ||
57 | _sclp_print_early(s); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | void *memset(void *s, int c, size_t n) | ||
62 | { | ||
63 | char *xs; | ||
64 | |||
65 | if (c == 0) | ||
66 | return __builtin_memset(s, 0, n); | ||
67 | |||
68 | xs = (char *) s; | ||
69 | if (n > 0) | ||
70 | do { | ||
71 | *xs++ = c; | ||
72 | } while (--n > 0); | ||
73 | return s; | ||
74 | } | ||
75 | |||
76 | void *memcpy(void *__dest, __const void *__src, size_t __n) | ||
77 | { | ||
78 | return __builtin_memcpy(__dest, __src, __n); | ||
79 | } | ||
80 | |||
81 | void *memmove(void *__dest, __const void *__src, size_t __n) | ||
82 | { | ||
83 | char *d; | ||
84 | const char *s; | ||
85 | |||
86 | if (__dest <= __src) | ||
87 | return __builtin_memcpy(__dest, __src, __n); | ||
88 | d = __dest + __n; | ||
89 | s = __src + __n; | ||
90 | while (__n--) | ||
91 | *--d = *--s; | ||
92 | return __dest; | ||
93 | } | ||
94 | |||
95 | static void error(char *x) | ||
96 | { | ||
97 | unsigned long long psw = 0x000a0000deadbeefULL; | ||
98 | |||
99 | puts("\n\n"); | ||
100 | puts(x); | ||
101 | puts("\n\n -- System halted"); | ||
102 | |||
103 | asm volatile("lpsw %0" : : "Q" (psw)); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * Safe guard the ipl parameter block against a memory area that will be | ||
108 | * overwritten. The validity check for the ipl parameter block is complex | ||
109 | * (see cio_get_iplinfo and ipl_save_parameters) but if the pointer to | ||
110 | * the ipl parameter block intersects with the passed memory area we can | ||
111 | * safely assume that we can read from that memory. In that case just copy | ||
112 | * the memory to IPL_PARMBLOCK_ORIGIN even if there is no ipl parameter | ||
113 | * block. | ||
114 | */ | ||
115 | static void check_ipl_parmblock(void *start, unsigned long size) | ||
116 | { | ||
117 | void *src, *dst; | ||
118 | |||
119 | src = (void *)(unsigned long) S390_lowcore.ipl_parmblock_ptr; | ||
120 | if (src + PAGE_SIZE <= start || src >= start + size) | ||
121 | return; | ||
122 | dst = (void *) IPL_PARMBLOCK_ORIGIN; | ||
123 | memmove(dst, src, PAGE_SIZE); | ||
124 | S390_lowcore.ipl_parmblock_ptr = IPL_PARMBLOCK_ORIGIN; | ||
125 | } | ||
126 | |||
127 | unsigned long decompress_kernel(void) | ||
128 | { | ||
129 | unsigned long output_addr; | ||
130 | unsigned char *output; | ||
131 | |||
132 | free_mem_ptr = (unsigned long)&_end; | ||
133 | free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; | ||
134 | output = (unsigned char *) ((free_mem_end_ptr + 4095UL) & -4096UL); | ||
135 | |||
136 | check_ipl_parmblock((void *) 0, (unsigned long) output + SZ__bss_start); | ||
137 | |||
138 | #ifdef CONFIG_BLK_DEV_INITRD | ||
139 | /* | ||
140 | * Move the initrd right behind the end of the decompressed | ||
141 | * kernel image. | ||
142 | */ | ||
143 | if (INITRD_START && INITRD_SIZE && | ||
144 | INITRD_START < (unsigned long) output + SZ__bss_start) { | ||
145 | check_ipl_parmblock(output + SZ__bss_start, | ||
146 | INITRD_START + INITRD_SIZE); | ||
147 | memmove(output + SZ__bss_start, | ||
148 | (void *) INITRD_START, INITRD_SIZE); | ||
149 | INITRD_START = (unsigned long) output + SZ__bss_start; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | puts("Uncompressing Linux... "); | ||
154 | decompress(input_data, input_len, NULL, NULL, output, NULL, error); | ||
155 | puts("Ok, booting the kernel.\n"); | ||
156 | return (unsigned long) output; | ||
157 | } | ||
158 | |||