Imported Upstream version 3.14
[debian/elilo] / x86_64 / bzimage.c
1 /*
2  *  Copyright (C) 2001-2003 Hewlett-Packard Co.
3  *      Contributed by Stephane Eranian <eranian@hpl.hp.com>
4  *      Contributed by Mike Johnston <johnston@intel.com>
5  *      Contributed by Chris Ahna <christopher.j.ahna@intel.com>
6  *
7  * This file is part of the ELILO, the EFI Linux boot loader.
8  *
9  *  ELILO is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2, or (at your option)
12  *  any later version.
13  *
14  *  ELILO is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with ELILO; see the file COPYING.  If not, write to the Free
21  *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22  *  02111-1307, USA.
23  *
24  * Please check out the elilo.txt for complete documentation on how
25  * to use this program.
26  */
27
28 #include <efi.h>
29 #include <efilib.h>
30
31 #include "elilo.h"
32 #include "loader.h"
33
34 boot_params_t *param_start = NULL;
35 UINTN param_size = 0;
36
37 UINTN kernel_size = 0x800000;   /* 8M (default x86_64 bzImage size limit) */
38
39 static VOID *
40 bzImage_alloc()
41 {
42         UINTN pages = EFI_SIZE_TO_PAGES(kernel_size);
43         int reloc_kernel = 0;
44         VOID *kla, *kend = kernel_start + kernel_size;
45         UINT32 kalign, kmask;
46         boot_params_t *ps = param_start;
47
48         /*
49          * Get address for kernel from header, if applicable & available.
50          */
51         if ((ps->s.hdr_major < 2) ||
52             (ps->s.hdr_major == 2 && ps->s.hdr_minor < 5)) {
53                 reloc_kernel = 0;
54         } else {
55                 if (ps->s.kernel_start >= DEFAULT_KERNEL_START)
56                         kernel_start = (void *)(UINT64)ps->s.kernel_start;
57                 reloc_kernel = ps->s.relocatable_kernel;
58                 kalign = ps->s.kernel_alignment;
59                 kmask = kalign - 1;
60                 VERB_PRT(3, Print(L"kernel header (%d.%d) suggests kernel "
61                         "start at address "PTR_FMT" (%srelocatable!)\n",
62                         ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start,
63                         (reloc_kernel ? L"": L"not ")));
64         }
65
66         /*
67          * Best effort for old (< 2.6.20) and non-relocatable kernels
68          */
69         if (alloc_kmem(kernel_start, pages) == 0) {
70                 VERB_PRT(3, Print(L"kernel_start: "PTR_FMT" kernel_size: %d\n",
71                         kernel_start, kernel_size));
72                 return kernel_start;
73         } else if ( ! reloc_kernel ) {
74                 /*
75                  * Couldn't get desired address--just load it anywhere and
76                  * (try to) move it later.  It's the only chance for non-
77                  * relocatable kernels, but it breaks occassionally...
78                  */
79                 ERR_PRT((L"Kernel header (%d.%d) suggests kernel "
80                         "start at address "PTR_FMT" (non relocatable!)\n"
81                         "This address is not available, so an attempt"
82                         "is made to copy the kernel there later on\n"
83                         "BEWARE: this is unsupported and may not work.  "
84                         "Please update your kernel.\n",
85                         ps->s.hdr_major, ps->s.hdr_minor, ps->s.kernel_start));
86                 kla = (VOID *)(UINT32_MAX - kernel_size);
87                 /* NULL would preserve the "anywhere" semantic, */
88                 /* but it would not prevent allocation above 4GB! */
89
90                 if (alloc_kmem_anywhere(&kla, pages) != 0) {
91                         /* out of luck */
92                         return NULL;
93                 }
94                 VERB_PRT(3, Print(L"kernel_start: "PTR_FMT
95                         "  kernel_size: %d  loading at: "PTR_FMT"\n",
96                         kernel_start, kernel_size, kla));
97                 return kla;
98         }
99
100
101         /* Is 'ps->s.kernel_alignment' guaranteed to be sane? */
102         if (kalign < EFI_PAGE_SIZE) {
103                 kalign = EFI_PAGE_SIZE;
104                 kmask = EFI_PAGE_MASK;
105         }
106         DBG_PRT((L"alignment: kernel=0x%x efi_page=0x%x : 0x%x\n",
107                 ps->s.kernel_alignment, EFI_PAGE_SIZE, kalign));
108
109         /*
110          * Couldn't get the preferred address, but luckily it's
111          * a relocatable kernel, so ...
112          *
113          * 1. use 'find_kernel_memory()' (like Itanium)
114          * 2. try out the 16 lowest possible aligned addresses (> 0)
115          * 3. get enough memory to align "creatively"
116          * 4. forget alignment (and start praying)...
117          */
118
119         /* 1. */
120         if ((find_kernel_memory(kernel_start, kend, kalign, &kla) != 0) ||
121             (alloc_kmem(kla, pages) != 0)) {
122                 kla = NULL;
123         }
124
125         /* 2. */
126         if ( ! kla && (UINT64)kernel_start < kalign ) {
127                 int i;
128                 for ( i = 1; i < 16 && !kla; i++ ) {
129                         VOID *tmp = (VOID *)((UINT64)kalign * i);
130                         if (alloc_kmem(tmp, pages) == 0) {
131                                 kla =  tmp;
132                         }
133                 }
134         }
135
136         /* 3. */
137         if ( ! kla ) {
138                 UINTN apages = EFI_SIZE_TO_PAGES(kernel_size + kmask);
139                 kla = (VOID *)(UINT32_MAX - kernel_size - kmask);
140
141                 if (alloc_kmem_anywhere(&kla, apages) == 0) {
142                         kla = (VOID *)(((UINT64)kla + kmask) & ~kmask);
143                 } else {
144                         kla = NULL;
145                 }
146         }
147
148         /* 4. last resort */
149         if ( ! kla ) {
150                 kla = (VOID *)(UINT32_MAX - kernel_size);
151                 if (alloc_kmem_anywhere(&kla, pages) != 0) {
152                         return NULL;
153                 }
154         }
155
156         kernel_start = kla;
157         VERB_PRT(1, Print(L"relocating kernel_start: "PTR_FMT
158                 "  kernel_size: %d\n", kernel_start, kernel_size));
159         return kla;
160 }
161
162 static INTN
163 bzImage_probe(CHAR16 *kname)
164 {
165         EFI_STATUS efi_status;
166         UINTN size;
167         fops_fd_t fd;
168         UINT8 bootsect[512];
169
170         DBG_PRT((L"probe_bzImage_boot()\n"));
171
172         if (!kname) {
173                 ERR_PRT((L"kname == %xh", kname));
174                 free_kmem();
175                 return -1;
176         }
177
178         /* 
179          * Open kernel image. 
180          */
181         DBG_PRT((L"opening %s...\n", kname));
182
183         efi_status = fops_open(kname, &fd);
184         if (EFI_ERROR(efi_status)) {
185                 ERR_PRT((L"Could not open %s.", kname));
186                 free_kmem();
187                 return -1;
188         }
189         /*
190          * Read boot sector.
191          */
192
193         DBG_PRT((L"\nreading boot sector...\n"));
194
195         size = sizeof bootsect;
196         efi_status = fops_read(fd, bootsect, &size);
197         if (EFI_ERROR(efi_status) || size != sizeof bootsect) {
198                 ERR_PRT((L"Could not read boot sector from %s.", kname));
199                 fops_close(fd);
200                 free_kmem();
201                 return -1;
202         }
203         /*
204          * Verify boot sector signature.
205          */
206
207         if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) {
208                 ERR_PRT((L"%s is not a bzImage kernel image.\n", kname));
209                 fops_close(fd);
210                 free_kmem();
211                 return -1;
212         }
213         /*
214          * Check for out of range setup data size.
215          * Will almost always be 7, but we will accept 1 to 64.
216          */
217
218         DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1]));
219
220         if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) {
221                 ERR_PRT((L"%s is not a valid bzImage kernel image.",
222                         kname));
223                 fops_close(fd);
224                 free_kmem();
225                 return -1;
226         }
227         /*
228          * Allocate and read setup data.
229          */
230
231         DBG_PRT((L"reading setup data...\n"));
232
233         param_size = (bootsect[0x1F1] + 1) * 512;
234         param_start = alloc(param_size, EfiLoaderData);
235
236         DBG_PRT((L"param_size=%d param_start=%x", param_size, param_start));
237
238         if (!param_start) {
239                 ERR_PRT((L"Could not allocate %d bytes of setup data.",
240                         param_size));
241                 fops_close(fd);
242                 free_kmem();
243                 return -1;
244         }
245
246         CopyMem(param_start, bootsect, sizeof bootsect);
247
248         size = param_size - 512;
249         efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size);
250
251         if (EFI_ERROR(efi_status) || size != param_size - 512) {
252                 ERR_PRT((L"Could not read %d bytes of setup data.",
253                         param_size - 512));
254                 free(param_start);
255                 param_start = NULL;
256                 param_size = 0;
257                 fops_close(fd);
258                 free_kmem();
259                 return -1;
260         }
261         /*
262          * Check for setup data signature.
263          */
264
265         { 
266                 UINT8 *c = ((UINT8 *)param_start)+514;
267                 DBG_PRT((L"param_start(c=%x): %c-%c-%c-%c", 
268                         c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3]));
269         }
270         if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) {
271                 ERR_PRT((L"%s does not have a setup signature.",
272                         kname));
273                 free(param_start);
274                 param_start = NULL;
275                 param_size = 0;
276                 fops_close(fd);
277                 free_kmem();
278                 return -1;
279         }
280         /*
281          * Allocate memory for kernel.
282          */
283
284         kernel_load_address = bzImage_alloc();
285         if ( ! kernel_load_address ) {
286                 ERR_PRT((L"Could not allocate memory for kernel."));
287                 free(param_start);
288                 param_start = NULL;
289                 param_size = 0;
290                 fops_close(fd);
291                 return -1;
292         }
293
294         /*
295          * Now read the rest of the kernel image into memory.
296          */
297
298         Print(L"Loading kernel %s... ", kname);
299
300         size = kernel_size;
301         efi_status = fops_read(fd, kernel_load_address, &size);
302         if (EFI_ERROR(efi_status) || size < 0x10000) {
303                 ERR_PRT((L"Error reading kernel image (0x%x).", efi_status));
304                 free(param_start);
305                 param_start = NULL;
306                 param_size = 0;
307                 fops_close(fd);
308                 free_kmem();
309                 return -1;
310         } else {
311                 Print(L" done\n");
312         }
313
314         DBG_PRT((L"kernel image read:  %d bytes, %d Kbytes\n", size, size / 1024));
315
316         /*
317          * Boot sector, setup data and kernel image loaded.
318          */
319
320         fops_close(fd);
321         return 0;
322 }
323
324 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
325 static INTN
326 bzImage_load(CHAR16 *kname, kdesc_t *kd)
327 {
328         DBG_PRT((L"load_bzImage_boot()\n"));
329
330         if (!kname || !kd) {
331                 ERR_PRT((L"kname="PTR_FMT"  kd="PTR_FMT"", kname, kd));
332                 free(param_start);
333                 param_start = NULL;
334                 param_size = 0;
335                 free_kmem();
336                 return -1;
337         }
338         kd->kstart = kd->kentry = kernel_start;
339         kd->kend = ((UINT8 *)kd->kstart) + kernel_size;
340
341         DBG_PRT((L"kstart="PTR_FMT"  kentry="PTR_FMT"  kend="PTR_FMT"\n", kd->kstart, kd->kentry, kd->kend));
342
343         return 0;
344 }
345
346 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
347 loader_ops_t bzimage_loader = {
348         NULL,
349         L"bzImage_loader",
350         &bzImage_probe,
351         &bzImage_load
352 };