Imported Upstream version 3.14
[debian/elilo] / ia32 / 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 = 0x400000;   /* 4M (default x86 bzImage size limit) */
38
39 static INTN
40 bzImage_probe(CHAR16 *kname)
41 {
42         EFI_STATUS efi_status;
43         UINTN size;
44         fops_fd_t fd;
45         UINT8 bootsect[512];
46
47         DBG_PRT((L"probe_bzImage_boot()\n"));
48
49         if (!kname) {
50                 ERR_PRT((L"kname == " PTR_FMT, kname));
51                 free_kmem();
52                 return -1;
53         }
54
55         /* 
56          * Open kernel image. 
57          */
58         DBG_PRT((L"opening %s...\n", kname));
59
60         efi_status = fops_open(kname, &fd);
61         if (EFI_ERROR(efi_status)) {
62                 ERR_PRT((L"Could not open %s.", kname));
63                 free_kmem();
64                 return -1;
65         }
66         /*
67          * Read boot sector.
68          */
69
70         DBG_PRT((L"\nreading boot sector...\n"));
71
72         size = sizeof bootsect;
73         efi_status = fops_read(fd, bootsect, &size);
74         if (EFI_ERROR(efi_status) || size != sizeof bootsect) {
75                 ERR_PRT((L"Could not read boot sector from %s.", kname));
76                 fops_close(fd);
77                 free_kmem();
78                 return -1;
79         }
80         /*
81          * Verify boot sector signature.
82          */
83
84         if (bootsect[0x1FE] != 0x55 || bootsect[0x1FF] != 0xAA) {
85                 ERR_PRT((L"%s is not a bzImage kernel image.\n", kname));
86                 fops_close(fd);
87                 free_kmem();
88                 return -1;
89         }
90         /*
91          * Check for out of range setup data size.
92          * Will almost always be 7, but we will accept 1 to 64.
93          */
94
95         DBG_PRT((L"bootsect[1F1h] == %d setup sectors\n", bootsect[0x1F1]));
96
97         if (bootsect[0x1F1] < 1 || bootsect[0x1F1] > 64) {
98                 ERR_PRT((L"%s is not a valid bzImage kernel image.",
99                         kname));
100                 fops_close(fd);
101                 free_kmem();
102                 return -1;
103         }
104         /*
105          * Allocate and read setup data.
106          */
107
108         DBG_PRT((L"reading setup data...\n"));
109
110         param_size = (bootsect[0x1F1] + 1) * 512;
111         param_start = alloc(param_size, EfiLoaderData);
112
113         DBG_PRT((L"param_size=%d param_start=" PTR_FMT, param_size, param_start));
114
115         if (!param_start) {
116                 ERR_PRT((L"Could not allocate %d bytes of setup data.",
117                         param_size));
118                 fops_close(fd);
119                 free_kmem();
120                 return -1;
121         }
122
123         CopyMem(param_start, bootsect, sizeof bootsect);
124
125         size = param_size - 512;
126         efi_status = fops_read(fd, ((UINT8 *)param_start) + 512, &size);
127
128         if (EFI_ERROR(efi_status) || size != param_size - 512) {
129                 ERR_PRT((L"Could not read %d bytes of setup data.",
130                         param_size - 512));
131                 free(param_start);
132                 param_start = NULL;
133                 param_size = 0;
134                 fops_close(fd);
135                 free_kmem();
136                 return -1;
137         }
138         /*
139          * Check for setup data signature.
140          */
141
142         { 
143                 UINT8 *c = ((UINT8 *)param_start)+514;
144                 DBG_PRT((L"param_start(c=" PTR_FMT "): %c-%c-%c-%c", 
145                         c, (CHAR16)c[0],(CHAR16) c[1], (CHAR16)c[2], (CHAR16)c[3]));
146         }
147         if (CompareMem(((UINT8 *)param_start) + 514, "HdrS", 4)) {
148                 ERR_PRT((L"%s does not have a setup signature.",
149                         kname));
150                 free(param_start);
151                 param_start = NULL;
152                 param_size = 0;
153                 fops_close(fd);
154                 free_kmem();
155                 return -1;
156         }
157         /*
158          * Allocate memory for kernel.
159          */
160
161         /*
162          * Get correct address for kernel from header, if applicable & available. 
163          */
164         if ((param_start->s.hdr_major == 2) &&
165             (param_start->s.hdr_minor >= 6) &&
166             (param_start->s.kernel_start >= DEFAULT_KERNEL_START)) {
167                 kernel_start = (void *)param_start->s.kernel_start;
168                 VERB_PRT(3, Print(L"kernel header suggests kernel start at address "PTR_FMT"\n",
169                         kernel_start));
170         }
171
172         kernel_load_address = NULL; /* allocate anywhere! */
173
174         if (alloc_kmem(kernel_start, EFI_SIZE_TO_PAGES(kernel_size)) != 0) {
175                 /*
176                  * Couldn't get desired address--just load it anywhere and move it later.
177                  * (Easier than relocating kernel, and also works with non-relocatable kernels.)
178                  */
179                 if (alloc_kmem_anywhere(&kernel_load_address, EFI_SIZE_TO_PAGES(kernel_size)) != 0) {
180                         ERR_PRT((L"Could not allocate memory for kernel."));
181                         free(param_start);
182                         param_start = NULL;
183                         param_size = 0;
184                         fops_close(fd);
185                         return -1;
186                 }
187         }
188
189         VERB_PRT(3, Print(L"kernel_start: "PTR_FMT"  kernel_size: %d  loading at: "PTR_FMT"\n",
190                 kernel_start, kernel_size, kernel_load_address));
191
192
193         /*
194          * Now read the rest of the kernel image into memory.
195          */
196
197         DBG_PRT((L"reading kernel image...\n"));
198
199         size = kernel_size;
200         efi_status = fops_read(fd, kernel_load_address, &size);
201         if (EFI_ERROR(efi_status) || size < 0x10000) {
202                 ERR_PRT((L"Error reading kernel image %s.", kname));
203                 free(param_start);
204                 param_start = NULL;
205                 param_size = 0;
206                 fops_close(fd);
207                 free_kmem();
208                 return -1;
209         }
210
211         DBG_PRT((L"kernel image read:  %d bytes, %d Kbytes\n", size, size / 1024));
212
213         /*
214          * Boot sector, setup data and kernel image loaded.
215          */
216
217         fops_close(fd);
218         return 0;
219 }
220
221 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
222 static INTN
223 bzImage_load(CHAR16 *kname, kdesc_t *kd)
224 {
225         DBG_PRT((L"load_bzImage_boot()\n"));
226
227         if (!kname || !kd) {
228                 ERR_PRT((L"kname=" PTR_FMT "  kd=" PTR_FMT, kname, kd));
229                 free(param_start);
230                 param_start = NULL;
231                 param_size = 0;
232                 free_kmem();
233                 return -1;
234         }
235         kd->kstart = kd->kentry = kernel_start;
236         kd->kend = ((UINT8 *)kd->kstart) + kernel_size;
237
238         DBG_PRT((L"kstart=" PTR_FMT "  kentry=" PTR_FMT "  kend=" PTR_FMT "\n", kd->kstart, kd->kentry, kd->kend));
239
240         return 0;
241 }
242
243 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
244 loader_ops_t bzimage_loader = {
245         NULL,
246         L"bzImage_loader",
247         &bzImage_probe,
248         &bzImage_load
249 };