0
|
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 };
|