227 |
big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL); |
big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL); |
228 |
lh->type_of_loader = LINUX_BOOT_LOADER_TYPE; |
lh->type_of_loader = LINUX_BOOT_LOADER_TYPE; |
229 |
|
|
230 |
|
/* Put the real mode part at as a high location as possible. */ |
231 |
|
linux_data_real_addr |
232 |
|
= (char *) ((mbi.mem_lower << 10) - LINUX_SETUP_MOVE_SIZE); |
233 |
|
/* But it must not exceed the traditional area. */ |
234 |
|
if (linux_data_real_addr > (char *) LINUX_OLD_REAL_MODE_ADDR) |
235 |
|
linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR; |
236 |
|
|
237 |
if (lh->version >= 0x0201) |
if (lh->version >= 0x0201) |
238 |
{ |
{ |
239 |
lh->heap_end_ptr = LINUX_HEAP_END_OFFSET; |
lh->heap_end_ptr = LINUX_HEAP_END_OFFSET; |
241 |
} |
} |
242 |
|
|
243 |
if (lh->version >= 0x0202) |
if (lh->version >= 0x0202) |
244 |
lh->cmd_line_ptr = CL_MY_LOCATION; |
lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET; |
245 |
else |
else |
246 |
{ |
{ |
247 |
lh->cl_magic = CL_MAGIC; |
lh->cl_magic = LINUX_CL_MAGIC; |
248 |
lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR; |
lh->cl_offset = LINUX_CL_OFFSET; |
249 |
lh->setup_move_size |
lh->setup_move_size = LINUX_SETUP_MOVE_SIZE; |
|
= (unsigned short) (CL_MY_END_ADDR - CL_BASE_ADDR + 1); |
|
250 |
} |
} |
251 |
} |
} |
252 |
else |
else |
253 |
{ |
{ |
254 |
/* Your kernel is quite old... */ |
/* Your kernel is quite old... */ |
255 |
lh->cl_magic = CL_MAGIC; |
lh->cl_magic = LINUX_CL_MAGIC; |
256 |
lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR; |
lh->cl_offset = LINUX_CL_OFFSET; |
257 |
|
|
258 |
setup_sects = LINUX_DEFAULT_SETUP_SECTS; |
setup_sects = LINUX_DEFAULT_SETUP_SECTS; |
259 |
|
|
260 |
|
linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR; |
261 |
} |
} |
262 |
|
|
263 |
/* If SETUP_SECTS is not set, set it to the default (4). */ |
/* If SETUP_SECTS is not set, set it to the default (4). */ |
266 |
|
|
267 |
data_len = setup_sects << 9; |
data_len = setup_sects << 9; |
268 |
text_len = filemax - data_len - SECTOR_SIZE; |
text_len = filemax - data_len - SECTOR_SIZE; |
269 |
|
|
270 |
|
linux_data_tmp_addr = (char *) LINUX_BZIMAGE_ADDR + text_len; |
271 |
|
|
272 |
if (! big_linux && text_len > LINUX_KERNEL_MAXLEN) |
if (! big_linux |
273 |
|
&& text_len > linux_data_real_addr - (char *) LINUX_ZIMAGE_ADDR) |
274 |
{ |
{ |
275 |
grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n"); |
grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n"); |
|
grub_close (); |
|
276 |
errnum = ERR_WONT_FIT; |
errnum = ERR_WONT_FIT; |
|
return KERNEL_TYPE_NONE; |
|
277 |
} |
} |
278 |
|
else if (linux_data_real_addr + LINUX_SETUP_MOVE_SIZE |
279 |
grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", |
> RAW_ADDR ((char *) (mbi.mem_lower << 10))) |
280 |
(big_linux ? "bzImage" : "zImage"), data_len, text_len); |
errnum = ERR_WONT_FIT; |
281 |
|
else |
|
/* FIXME: SETUP_SECTS should be supported up to 63. |
|
|
But do you know there are >640KB conventional memory machines? */ |
|
|
if (mbi.mem_lower >= 608 && setup_sects < 60) |
|
282 |
{ |
{ |
283 |
|
grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", |
284 |
|
(big_linux ? "bzImage" : "zImage"), data_len, text_len); |
285 |
|
|
286 |
/* Video mode selection support. What a mess! */ |
/* Video mode selection support. What a mess! */ |
287 |
/* NOTE: Even the word "mess" is not still enough to |
/* NOTE: Even the word "mess" is not still enough to |
288 |
represent how wrong and bad the Linux video support is, |
represent how wrong and bad the Linux video support is, |
290 |
any more. -okuji */ |
any more. -okuji */ |
291 |
{ |
{ |
292 |
char *vga; |
char *vga; |
293 |
|
|
294 |
/* Find the substring "vga=". */ |
/* Find the substring "vga=". */ |
295 |
vga = grub_strstr (arg, "vga="); |
vga = grub_strstr (arg, "vga="); |
296 |
if (vga) |
if (vga) |
297 |
{ |
{ |
298 |
char *value = vga + 4; |
char *value = vga + 4; |
299 |
int vid_mode; |
int vid_mode; |
300 |
|
|
301 |
/* Handle special strings. */ |
/* Handle special strings. */ |
302 |
if (substring ("normal", value) < 1) |
if (substring ("normal", value) < 1) |
303 |
vid_mode = LINUX_VID_MODE_NORMAL; |
vid_mode = LINUX_VID_MODE_NORMAL; |
314 |
grub_close (); |
grub_close (); |
315 |
return KERNEL_TYPE_NONE; |
return KERNEL_TYPE_NONE; |
316 |
} |
} |
317 |
|
|
318 |
lh->vid_mode = vid_mode; |
lh->vid_mode = vid_mode; |
319 |
} |
} |
320 |
} |
} |
322 |
/* Check the mem= option to limit memory used for initrd. */ |
/* Check the mem= option to limit memory used for initrd. */ |
323 |
{ |
{ |
324 |
char *mem; |
char *mem; |
325 |
|
|
326 |
mem = grub_strstr (arg, "mem="); |
mem = grub_strstr (arg, "mem="); |
327 |
if (mem) |
if (mem) |
328 |
{ |
{ |
329 |
char *value = mem + 4; |
char *value = mem + 4; |
330 |
|
|
331 |
safe_parse_maxint (&value, &linux_mem_size); |
safe_parse_maxint (&value, &linux_mem_size); |
332 |
switch (errnum) |
switch (errnum) |
333 |
{ |
{ |
338 |
linux_mem_size = LINUX_INITRD_MAX_ADDRESS; |
linux_mem_size = LINUX_INITRD_MAX_ADDRESS; |
339 |
errnum = ERR_NONE; |
errnum = ERR_NONE; |
340 |
break; |
break; |
341 |
|
|
342 |
case ERR_NONE: |
case ERR_NONE: |
343 |
{ |
{ |
344 |
int shift = 0; |
int shift = 0; |
345 |
|
|
346 |
switch (grub_tolower (*value)) |
switch (grub_tolower (*value)) |
347 |
{ |
{ |
348 |
case 'g': |
case 'g': |
354 |
default: |
default: |
355 |
break; |
break; |
356 |
} |
} |
357 |
|
|
358 |
/* Check an overflow. */ |
/* Check an overflow. */ |
359 |
if (linux_mem_size > (MAXINT >> shift)) |
if (linux_mem_size > (MAXINT >> shift)) |
360 |
linux_mem_size = LINUX_INITRD_MAX_ADDRESS; |
linux_mem_size = LINUX_INITRD_MAX_ADDRESS; |
362 |
linux_mem_size <<= shift; |
linux_mem_size <<= shift; |
363 |
} |
} |
364 |
break; |
break; |
365 |
|
|
366 |
default: |
default: |
367 |
linux_mem_size = 0; |
linux_mem_size = 0; |
368 |
errnum = ERR_NONE; |
errnum = ERR_NONE; |
372 |
else |
else |
373 |
linux_mem_size = 0; |
linux_mem_size = 0; |
374 |
} |
} |
375 |
|
|
376 |
/* It is possible that DATA_LEN is greater than MULTIBOOT_SEARCH, |
/* It is possible that DATA_LEN is greater than MULTIBOOT_SEARCH, |
377 |
so the data may have been read partially. */ |
so the data may have been read partially. */ |
378 |
if (data_len <= MULTIBOOT_SEARCH) |
if (data_len <= MULTIBOOT_SEARCH) |
379 |
grub_memmove ((char *) LINUX_SETUP, buffer, |
grub_memmove (linux_data_tmp_addr, buffer, |
380 |
data_len + SECTOR_SIZE); |
data_len + SECTOR_SIZE); |
381 |
else |
else |
382 |
{ |
{ |
383 |
grub_memmove ((char *) LINUX_SETUP, buffer, MULTIBOOT_SEARCH); |
grub_memmove (linux_data_tmp_addr, buffer, MULTIBOOT_SEARCH); |
384 |
grub_read ((char *) LINUX_SETUP + MULTIBOOT_SEARCH, |
grub_read (linux_data_tmp_addr + MULTIBOOT_SEARCH, |
385 |
data_len + SECTOR_SIZE - MULTIBOOT_SEARCH); |
data_len + SECTOR_SIZE - MULTIBOOT_SEARCH); |
386 |
} |
} |
387 |
|
|
388 |
if (lh->header != LINUX_MAGIC_SIGNATURE || |
if (lh->header != LINUX_MAGIC_SIGNATURE || |
389 |
lh->version < 0x0200) |
lh->version < 0x0200) |
390 |
/* Clear the heap space. */ |
/* Clear the heap space. */ |
391 |
grub_memset ((char *) LINUX_SETUP + ((setup_sects - 1) << 9), |
grub_memset (linux_data_tmp_addr + ((setup_sects + 1) << 9), |
392 |
0, |
0, |
393 |
(64 - setup_sects - 1) << 9); |
(64 - setup_sects - 1) << 9); |
394 |
|
|
395 |
/* Copy command-line plus memory hack to staging area. |
/* Copy command-line plus memory hack to staging area. |
396 |
NOTE: Linux has a bug that it doesn't handle multiple spaces |
NOTE: Linux has a bug that it doesn't handle multiple spaces |
397 |
between two options and a space after a "mem=" option isn't |
between two options and a space after a "mem=" option isn't |
402 |
avoid to copy spaces unnecessarily. Hell. */ |
avoid to copy spaces unnecessarily. Hell. */ |
403 |
{ |
{ |
404 |
char *src = skip_to (0, arg); |
char *src = skip_to (0, arg); |
405 |
char *dest = (char *) CL_MY_LOCATION; |
char *dest = linux_data_tmp_addr + LINUX_CL_OFFSET; |
406 |
|
|
407 |
while (((int) dest) < CL_MY_END_ADDR && *src) |
while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src) |
408 |
*(dest++) = *(src++); |
*(dest++) = *(src++); |
409 |
|
|
410 |
/* Add a mem option automatically only if the user doesn't |
/* Add a mem option automatically only if the user doesn't |
411 |
specify it explicitly. */ |
specify it explicitly. */ |
412 |
if (! grub_strstr (arg, "mem=") |
if (! grub_strstr (arg, "mem=") |
413 |
&& ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION)) |
&& ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION) |
414 |
|
&& dest + 15 < linux_data_tmp_addr + LINUX_CL_END_OFFSET) |
415 |
{ |
{ |
416 |
if (dest != (char *) CL_MY_LOCATION) |
*dest++ = ' '; |
417 |
*(dest++) = ' '; |
*dest++ = 'm'; |
418 |
|
*dest++ = 'e'; |
419 |
grub_memmove (dest, "mem=", 4); |
*dest++ = 'm'; |
420 |
dest += 4; |
*dest++ = '='; |
421 |
|
|
422 |
dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400)); |
dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400)); |
423 |
*(dest++) = 'K'; |
*dest++ = 'K'; |
424 |
} |
} |
425 |
|
|
426 |
*dest = 0; |
*dest = 0; |
427 |
} |
} |
428 |
|
|
429 |
/* offset into file */ |
/* offset into file */ |
430 |
grub_seek (data_len + SECTOR_SIZE); |
grub_seek (data_len + SECTOR_SIZE); |
431 |
|
|
432 |
cur_addr = LINUX_STAGING_AREA + text_len; |
cur_addr = (int) linux_data_tmp_addr + LINUX_SETUP_MOVE_SIZE; |
433 |
grub_read ((char *) LINUX_STAGING_AREA, text_len); |
grub_read ((char *) LINUX_BZIMAGE_ADDR, text_len); |
434 |
|
|
435 |
if (errnum == ERR_NONE) |
if (errnum == ERR_NONE) |
436 |
{ |
{ |
437 |
grub_close (); |
grub_close (); |
438 |
|
|
439 |
/* Sanity check. */ |
/* Sanity check. */ |
440 |
if (suggested_type != KERNEL_TYPE_NONE |
if (suggested_type != KERNEL_TYPE_NONE |
441 |
&& ((big_linux && suggested_type != KERNEL_TYPE_BIG_LINUX) |
&& ((big_linux && suggested_type != KERNEL_TYPE_BIG_LINUX) |
444 |
errnum = ERR_EXEC_FORMAT; |
errnum = ERR_EXEC_FORMAT; |
445 |
return KERNEL_TYPE_NONE; |
return KERNEL_TYPE_NONE; |
446 |
} |
} |
447 |
|
|
448 |
/* Ugly hack. */ |
/* Ugly hack. */ |
449 |
linux_text_len = text_len; |
linux_text_len = text_len; |
450 |
|
|
451 |
return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX; |
return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX; |
452 |
} |
} |
|
|
|
|
grub_close (); |
|
453 |
} |
} |
|
else |
|
|
errnum = ERR_WONT_FIT; |
|
454 |
} |
} |
455 |
else /* no recognizable format */ |
else /* no recognizable format */ |
456 |
errnum = ERR_EXEC_FORMAT; |
errnum = ERR_EXEC_FORMAT; |
786 |
{ |
{ |
787 |
int len; |
int len; |
788 |
unsigned long moveto; |
unsigned long moveto; |
789 |
struct linux_kernel_header *lh; |
struct linux_kernel_header *lh |
790 |
|
= (struct linux_kernel_header *) (cur_addr - LINUX_SETUP_MOVE_SIZE); |
791 |
|
|
792 |
#ifndef NO_DECOMPRESSION |
#ifndef NO_DECOMPRESSION |
793 |
no_decompression = 1; |
no_decompression = 1; |
822 |
printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len); |
printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len); |
823 |
|
|
824 |
/* FIXME: Should check if the kernel supports INITRD. */ |
/* FIXME: Should check if the kernel supports INITRD. */ |
|
lh = (struct linux_kernel_header *) LINUX_SETUP; |
|
825 |
lh->ramdisk_image = RAW_ADDR (moveto); |
lh->ramdisk_image = RAW_ADDR (moveto); |
826 |
lh->ramdisk_size = len; |
lh->ramdisk_size = len; |
827 |
|
|