48 |
{ |
{ |
49 |
kernel_entry_t linuxmain; |
kernel_entry_t linuxmain; |
50 |
grub_size_t actual; |
grub_size_t actual; |
51 |
|
|
52 |
/* Set the command line arguments. */ |
/* Set the command line arguments. */ |
53 |
grub_ieee1275_set_property (grub_ieee1275_chosen, "bootargs", linux_args, |
grub_ieee1275_set_property (grub_ieee1275_chosen, "bootargs", linux_args, |
54 |
grub_strlen (linux_args) + 1, &actual); |
grub_strlen (linux_args) + 1, &actual); |
55 |
|
|
56 |
|
grub_dprintf ("loader", "Entry point: 0x%x\n", linux_addr); |
57 |
|
grub_dprintf ("loader", "Initrd at: 0x%x, size 0x%x\n", initrd_addr, |
58 |
|
initrd_size); |
59 |
|
grub_dprintf ("loader", "Boot arguments: %s\n", linux_args); |
60 |
|
grub_dprintf ("loader", "Jumping to Linux...\n"); |
61 |
|
|
62 |
/* Boot the kernel. */ |
/* Boot the kernel. */ |
63 |
linuxmain = (kernel_entry_t) linux_addr; |
linuxmain = (kernel_entry_t) linux_addr; |
64 |
linuxmain ((void *) initrd_addr, initrd_size, grub_ieee1275_entry_fn, 0, 0); |
linuxmain ((void *) initrd_addr, initrd_size, grub_ieee1275_entry_fn, 0, 0); |
71 |
{ |
{ |
72 |
grub_free (linux_args); |
grub_free (linux_args); |
73 |
linux_args = 0; |
linux_args = 0; |
74 |
|
|
75 |
if (linux_addr && grub_ieee1275_release (linux_addr, linux_size)) |
if (linux_addr && grub_ieee1275_release (linux_addr, linux_size)) |
76 |
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory"); |
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory"); |
77 |
|
|
78 |
if (initrd_addr && grub_ieee1275_release (initrd_addr, initrd_size)) |
if (initrd_addr && grub_ieee1275_release (initrd_addr, initrd_size)) |
79 |
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory"); |
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory"); |
80 |
|
|
81 |
linux_addr = 0; |
linux_addr = 0; |
82 |
initrd_addr = 0; |
initrd_addr = 0; |
83 |
|
|
84 |
return GRUB_ERR_NONE; |
return GRUB_ERR_NONE; |
85 |
} |
} |
86 |
|
|
88 |
grub_linux_unload (void) |
grub_linux_unload (void) |
89 |
{ |
{ |
90 |
grub_err_t err; |
grub_err_t err; |
91 |
|
|
92 |
err = grub_linux_release_mem (); |
err = grub_linux_release_mem (); |
93 |
grub_dl_unref (my_mod); |
grub_dl_unref (my_mod); |
94 |
|
|
95 |
loaded = 0; |
loaded = 0; |
96 |
|
|
97 |
return err; |
return err; |
98 |
} |
} |
99 |
|
|
103 |
grub_file_t file = 0; |
grub_file_t file = 0; |
104 |
Elf32_Ehdr ehdr; |
Elf32_Ehdr ehdr; |
105 |
Elf32_Phdr *phdrs = 0; |
Elf32_Phdr *phdrs = 0; |
106 |
int i; |
int i; |
107 |
int offset = 0; |
int offset = 0; |
108 |
grub_addr_t entry; |
grub_addr_t entry; |
109 |
int found_addr = 0; |
int found_addr = 0; |
110 |
int size; |
int size; |
111 |
|
|
112 |
grub_dl_ref (my_mod); |
grub_dl_ref (my_mod); |
113 |
|
|
114 |
if (argc == 0) |
if (argc == 0) |
116 |
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); |
grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); |
117 |
goto fail; |
goto fail; |
118 |
} |
} |
119 |
|
|
120 |
file = grub_file_open (argv[0]); |
file = grub_file_open (argv[0]); |
121 |
if (! file) |
if (! file) |
122 |
goto fail; |
goto fail; |
123 |
|
|
124 |
if (grub_file_read (file, (char *) &ehdr, sizeof (ehdr)) != sizeof (ehdr)) |
if (grub_file_read (file, (char *) &ehdr, sizeof (ehdr)) != sizeof (ehdr)) |
125 |
{ |
{ |
126 |
grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux elf header"); |
grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux elf header"); |
127 |
goto fail; |
goto fail; |
128 |
} |
} |
129 |
|
|
130 |
if (grub_dl_check_header (&ehdr, sizeof(ehdr))) |
if (grub_dl_check_header (&ehdr, sizeof(ehdr))) |
131 |
{ |
{ |
132 |
grub_error (GRUB_ERR_UNKNOWN_OS, "No valid ELF header found"); |
grub_error (GRUB_ERR_UNKNOWN_OS, "No valid ELF header found"); |
133 |
goto fail; |
goto fail; |
134 |
} |
} |
135 |
|
|
136 |
if (ehdr.e_type != ET_EXEC) |
if (ehdr.e_type != ET_EXEC) |
137 |
{ |
{ |
138 |
grub_error (GRUB_ERR_UNKNOWN_OS, |
grub_error (GRUB_ERR_UNKNOWN_OS, |
152 |
|
|
153 |
phdrs = (Elf32_Phdr *) grub_malloc (ehdr.e_phnum * ehdr.e_phentsize); |
phdrs = (Elf32_Phdr *) grub_malloc (ehdr.e_phnum * ehdr.e_phentsize); |
154 |
grub_file_read (file, (void *) phdrs, ehdr.e_phnum * ehdr.e_phentsize); |
grub_file_read (file, (void *) phdrs, ehdr.e_phnum * ehdr.e_phentsize); |
155 |
|
|
156 |
/* Release the previously used memory. */ |
/* Release the previously used memory. */ |
157 |
grub_loader_unset (); |
grub_loader_unset (); |
158 |
|
|
159 |
/* Determine the amount of memory that is required. */ |
/* Determine the amount of memory that is required. */ |
160 |
linux_size = 0; |
linux_size = 0; |
161 |
for (i = 0; i < ehdr.e_phnum; i++) |
for (i = 0; i < ehdr.e_phnum; i++) |
164 |
/* XXX: Is this calculation correct? */ |
/* XXX: Is this calculation correct? */ |
165 |
linux_size += phdr->p_memsz + phdr->p_filesz; |
linux_size += phdr->p_memsz + phdr->p_filesz; |
166 |
} |
} |
167 |
|
|
168 |
/* Reserve memory for the kernel. */ |
/* Reserve memory for the kernel. */ |
169 |
linux_size += 0x100000; |
linux_size += 0x100000; |
170 |
|
|
171 |
/* For some vmlinux kernels the address set above won't work. Just |
/* For some vmlinux kernels the address set above won't work. Just |
172 |
try some other addresses just like yaboot does. */ |
try some other addresses just like yaboot does. */ |
173 |
for (linux_addr = entry; linux_addr < entry + 200 * 0x100000; linux_addr += 0x100000) |
for (linux_addr = entry; linux_addr < entry + 200 * 0x100000; linux_addr += 0x100000) |
183 |
goto fail; |
goto fail; |
184 |
} |
} |
185 |
entry = linux_addr; |
entry = linux_addr; |
186 |
|
|
187 |
/* Load every loadable segment in memory. */ |
/* Load every loadable segment in memory. */ |
188 |
for (i = 0; i < ehdr.e_phnum; i++) |
for (i = 0; i < ehdr.e_phnum; i++) |
189 |
{ |
{ |
191 |
|
|
192 |
if (phdr->p_type == PT_LOAD) |
if (phdr->p_type == PT_LOAD) |
193 |
{ |
{ |
194 |
|
void *segment_addr = ((char *) entry) + offset; |
195 |
|
|
196 |
if (grub_file_seek (file, phdr->p_offset) == -1) |
if (grub_file_seek (file, phdr->p_offset) == -1) |
197 |
{ |
{ |
198 |
grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program header"); |
grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program header"); |
199 |
goto fail; |
goto fail; |
200 |
} |
} |
201 |
|
|
202 |
if (grub_file_read (file, (void *) (((char *) entry) + offset) , phdr->p_filesz) |
grub_dprintf ("loader", "Loading segment %d at %p, size 0x%x\n", i, |
203 |
|
segment_addr, phdr->p_filesz); |
204 |
|
|
205 |
|
if (grub_file_read (file, segment_addr, phdr->p_filesz) |
206 |
!= (grub_ssize_t) phdr->p_filesz) |
!= (grub_ssize_t) phdr->p_filesz) |
207 |
goto fail; |
goto fail; |
208 |
|
|
209 |
if (phdr->p_filesz < phdr->p_memsz) |
if (phdr->p_filesz < phdr->p_memsz) |
210 |
grub_memset ((char *) (((char *) entry) + offset) + phdr->p_filesz, 0, |
grub_memset ((char *) (((char *) entry) + offset) + phdr->p_filesz, 0, |
211 |
phdr->p_memsz - phdr->p_filesz); |
phdr->p_memsz - phdr->p_filesz); |
212 |
|
|
213 |
offset += phdr->p_filesz; |
offset += phdr->p_filesz; |
214 |
} |
} |
215 |
} |
} |
216 |
|
|
217 |
size = 0; |
size = 0; |
218 |
for (i = 0; i < argc; i++) |
for (i = 0; i < argc; i++) |
219 |
size += grub_strlen (argv[i]); |
size += grub_strlen (argv[i]); |
220 |
|
|
221 |
linux_args = grub_malloc (size + argc + 1); |
linux_args = grub_malloc (size + argc + 1); |
222 |
if (!linux_args) |
if (!linux_args) |
223 |
goto fail; |
goto fail; |
224 |
|
|
225 |
for (i = 1; i < argc; i++) |
for (i = 1; i < argc; i++) |
226 |
{ |
{ |
227 |
grub_strcat (linux_args, argv[i]); |
grub_strcat (linux_args, argv[i]); |
228 |
grub_strcat (linux_args, " "); |
grub_strcat (linux_args, " "); |
229 |
} |
} |
230 |
|
|
231 |
fail: |
fail: |
232 |
|
|
233 |
if (file) |
if (file) |
234 |
grub_file_close (file); |
grub_file_close (file); |
235 |
|
|
236 |
grub_free (phdrs); |
grub_free (phdrs); |
237 |
|
|
238 |
if (grub_errno != GRUB_ERR_NONE) |
if (grub_errno != GRUB_ERR_NONE) |
247 |
initrd_addr = 0; |
initrd_addr = 0; |
248 |
loaded = 1; |
loaded = 1; |
249 |
} |
} |
250 |
|
|
251 |
return; |
return; |
252 |
} |
} |
253 |
|
|
257 |
grub_file_t file = 0; |
grub_file_t file = 0; |
258 |
grub_ssize_t size; |
grub_ssize_t size; |
259 |
grub_addr_t addr; |
grub_addr_t addr; |
260 |
|
|
261 |
if (argc == 0) |
if (argc == 0) |
262 |
{ |
{ |
263 |
grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified"); |
grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified"); |
264 |
goto fail; |
goto fail; |
265 |
} |
} |
266 |
|
|
267 |
if (!loaded) |
if (!loaded) |
268 |
{ |
{ |
269 |
grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); |
grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); |
273 |
file = grub_file_open (argv[0]); |
file = grub_file_open (argv[0]); |
274 |
if (! file) |
if (! file) |
275 |
goto fail; |
goto fail; |
276 |
|
|
277 |
addr = linux_addr + linux_size; |
addr = linux_addr + linux_size; |
278 |
size = grub_file_size (file); |
size = grub_file_size (file); |
279 |
|
|
280 |
if (grub_claimmap (addr, size) == -1) |
if (grub_claimmap (addr, size) == -1) |
281 |
{ |
{ |
282 |
grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not claim memory"); |
grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not claim memory"); |
283 |
goto fail; |
goto fail; |
284 |
} |
} |
285 |
|
|
286 |
|
grub_dprintf ("loader", "Loading initrd at 0x%x, size 0x%x\n", addr, size); |
287 |
|
|
288 |
if (grub_file_read (file, (void *) addr, size) != size) |
if (grub_file_read (file, (void *) addr, size) != size) |
289 |
{ |
{ |
290 |
grub_ieee1275_release (addr, size); |
grub_ieee1275_release (addr, size); |
291 |
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); |
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); |
292 |
goto fail; |
goto fail; |
293 |
} |
} |
294 |
|
|
295 |
initrd_addr = addr; |
initrd_addr = addr; |
296 |
initrd_size = size; |
initrd_size = size; |
297 |
|
|
298 |
fail: |
fail: |
299 |
if (file) |
if (file) |
300 |
grub_file_close (file); |
grub_file_close (file); |