grub/loader/i386/pc/linux.c

307 lines
7.8 KiB
C
Raw Normal View History

2003-01-17 Yoshinori K. Okuji <okuji@enbug.org> * include/pupa/i386/pc/linux.h: New file. * loader/i386/pc/linux.c: Likewise. * loader/i386/pc/chainloader.c (pupa_chainloader_boot_sector): Removed. (pupa_chainloader_unload): Return PUPA_ERR_NONE. (pupa_rescue_cmd_chainloader): Read the image to 0x7C00 instead of PUPA_CHAINLOADER_BOOT_SECTOR. * kern/i386/pc/startup.S: Include pupa/machine/linux.h. (pupa_linux_prot_size): New variable. (pupa_linux_tmp_addr): Likewise. (pupa_linux_real_addr): Likewise. (pupa_linux_boot_zimage): New function. (pupa_linux_boot_bzimage): Likewise. * kern/i386/pc/init.c (struct mem_region): New structure. (MAX_REGIONS): New macro. (mem_regions): New variable. (num_regions): Likewise. (pupa_os_area_addr): Likewise. (pupa_os_area_size): Likewise. (pupa_lower_mem): Likewise. (pupa_upper_mem): Likewise. (add_mem_region): New function. (compact_mem_regions): Likewise. (pupa_machine_init): Set PUPA_LOWER_MEM and PUPA_UPPER_MEM to the size of the conventional memory and that of so-called upper memory (before the first memory hole). Instead of adding each found region to free memory, use add_mem_region and add them after removing overlaps. Also, add only 1/4 of the upper memory to free memory. The rest is used for loading OS images. Maybe this is ad hoc, but this makes it much easier to relocate OS images when booting. * kern/rescue.c (pupa_rescue_cmd_module): Removed. (pupa_enter_rescue_mode): Don't register initrd and module. * kern/mm.c: Include pupa/dl.h. * kern/main.c: Include pupa/file.h and pupa/device.h. * kern/loader.c (pupa_loader_load_module_func): Removed. (pupa_loader_load_module): Likewise. * kern/dl.c (pupa_dl_load): Use the suffix ``.mod'' instead of ``.o''. * include/pupa/i386/pc/loader.h (pupa_linux_prot_size): Declared. (pupa_linux_tmp_addr): Likewise. (pupa_linux_real_addr): Likewise. (pupa_linux_boot_zimage): Likewise. (pupa_linux_boot_bzimage): Likewise. * include/pupa/i386/pc/init.h (pupa_lower_mem): Declared. (pupa_upper_mem): Likewise. (pupa_gate_a20): Don't export, because turning off Gate A20 in a module is too dangerous. * include/pupa/loader.h (pupa_os_area_addr): Declared. (pupa_os_area_size): Likewise. (pupa_loader_set): Remove the first argument. Loader doesn't manage modules or initrd any longer. (pupa_loader_load_module): Removed. * conf/i386-pc.rmk (pkgdata_MODULES): Added linux.mod. (linux_mod_SOURCES): New variable. (linux_mod_CFLAGS): Likewise.
2003-01-17 02:52:05 +00:00
/* linux.c - boot Linux zImage or bzImage */
/*
* PUPA -- Preliminary Universal Programming Architecture for GRUB
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
* Copyright (C) 2003 Yoshinori K. Okuji <okuji@enbug.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <pupa/loader.h>
#include <pupa/machine/loader.h>
#include <pupa/file.h>
#include <pupa/err.h>
#include <pupa/device.h>
#include <pupa/disk.h>
#include <pupa/misc.h>
#include <pupa/types.h>
#include <pupa/machine/init.h>
#include <pupa/machine/memory.h>
#include <pupa/rescue.h>
#include <pupa/dl.h>
#include <pupa/machine/linux.h>
static pupa_dl_t my_mod;
static int big_linux;
static pupa_size_t linux_mem_size;
static int loaded;
static pupa_err_t
pupa_linux_boot (void)
{
if (big_linux)
pupa_linux_boot_bzimage ();
else
pupa_linux_boot_zimage ();
/* Never reach here. */
return PUPA_ERR_NONE;
}
static pupa_err_t
pupa_linux_unload (void)
{
pupa_dl_unref (my_mod);
loaded = 0;
return PUPA_ERR_NONE;
}
2003-01-20 Yoshinori K. Okuji <okuji@enbug.org> * include/pupa/normal.h: New file. * include/pupa/setjmp.h: Likewise. * include/pupa/i386/setjmp.h: Likewise. * normal/cmdline.c: Likewise. * normal/command.c: Likewise. * normal/main.c: Likewise. * normal/menu.c: Likewise. * normal/i386/setjmp.S: Likewise. * loader/i386/pc/linux.c (pupa_rescue_cmd_linux): Made global. (pupa_rescue_cmd_initrd): Likewise. * loader/i386/pc/chainloader.c (pupa_rescue_cmd_chainloader): Likewise. * kern/i386/pc/startup.S (translation_table): New variable. (translate_keycode): New function. (pupa_console_getkey): Call translate_keycode. * kern/rescue.c (attempt_normal_mode): New function. (pupa_enter_rescue_mode): Attempt to execute the normal mode. If it failed, print a message. * kern/mm.c (pupa_real_malloc): Print more information when a free magic is broken. (pupa_free): If the first free header is not free actually, set it to P. * kern/main.c (pupa_load_normal_mode): Just load the module "normal". (pupa_main): Don't print the message "Entering into rescue mode..." here. * include/pupa/i386/pc/loader.h (pupa_rescue_cmd_initrd): Declared. (pupa_rescue_cmd_initrd): Likewise. (pupa_rescue_cmd_initrd): Likewise. * include/pupa/symbol.h (FUNCTION): Specify the type. (VARIABLE): Likewise. * include/pupa/err.h (pupa_err_t): Added PUPA_ERR_UNKNOWN_COMMAND. * include/pupa/dl.h (pupa_dl_set_prefix): Exported. (pupa_dl_get_prefix): Likewise. * conf/i386-pc.rmk (pkgdata_MODULES): Added normal.mod. Added _chain.mod and _linux.mod instead of chain.mod and linux.mod. (chain_mod_SOURCES): Renamed to ... (_chain_mod_SOURCES): ... this. (chain_mod_CFLAGS): Renamed to ... (_chain_mod_CFLAGS): ... this. (linux_mod_SOURCES): Renamed to ... (_linux_mod_SOURCES): ... this. (linux_mod_CFLAGS): Renamed to ... (_linux_mod_CFLAGS): ... this. (normal_mod_SOURCES): New variable. (normal_mod_CFLAGS): Likewise. (normal_mod_ASFLAGS): Likewise. 2003-01-18 Yoshinori K. Okuji <okuji@enbug.org> * kern/rescue.c (pupa_rescue_cmd_rmmod): Call pupa_dl_unload, if possible. * kern/dl.c (pupa_dl_ref): Refer dependending modules recursively. (pupa_dl_unref): Unrefer depending modules recursively. Don't call pupa_dl_unload implicitly, because PUPA can crash if a module is unloaded before one depending on that module is unloaded. (pupa_dl_unload): Unload depending modules explicitly, if possible.
2003-01-20 04:13:46 +00:00
void
2003-01-17 Yoshinori K. Okuji <okuji@enbug.org> * include/pupa/i386/pc/linux.h: New file. * loader/i386/pc/linux.c: Likewise. * loader/i386/pc/chainloader.c (pupa_chainloader_boot_sector): Removed. (pupa_chainloader_unload): Return PUPA_ERR_NONE. (pupa_rescue_cmd_chainloader): Read the image to 0x7C00 instead of PUPA_CHAINLOADER_BOOT_SECTOR. * kern/i386/pc/startup.S: Include pupa/machine/linux.h. (pupa_linux_prot_size): New variable. (pupa_linux_tmp_addr): Likewise. (pupa_linux_real_addr): Likewise. (pupa_linux_boot_zimage): New function. (pupa_linux_boot_bzimage): Likewise. * kern/i386/pc/init.c (struct mem_region): New structure. (MAX_REGIONS): New macro. (mem_regions): New variable. (num_regions): Likewise. (pupa_os_area_addr): Likewise. (pupa_os_area_size): Likewise. (pupa_lower_mem): Likewise. (pupa_upper_mem): Likewise. (add_mem_region): New function. (compact_mem_regions): Likewise. (pupa_machine_init): Set PUPA_LOWER_MEM and PUPA_UPPER_MEM to the size of the conventional memory and that of so-called upper memory (before the first memory hole). Instead of adding each found region to free memory, use add_mem_region and add them after removing overlaps. Also, add only 1/4 of the upper memory to free memory. The rest is used for loading OS images. Maybe this is ad hoc, but this makes it much easier to relocate OS images when booting. * kern/rescue.c (pupa_rescue_cmd_module): Removed. (pupa_enter_rescue_mode): Don't register initrd and module. * kern/mm.c: Include pupa/dl.h. * kern/main.c: Include pupa/file.h and pupa/device.h. * kern/loader.c (pupa_loader_load_module_func): Removed. (pupa_loader_load_module): Likewise. * kern/dl.c (pupa_dl_load): Use the suffix ``.mod'' instead of ``.o''. * include/pupa/i386/pc/loader.h (pupa_linux_prot_size): Declared. (pupa_linux_tmp_addr): Likewise. (pupa_linux_real_addr): Likewise. (pupa_linux_boot_zimage): Likewise. (pupa_linux_boot_bzimage): Likewise. * include/pupa/i386/pc/init.h (pupa_lower_mem): Declared. (pupa_upper_mem): Likewise. (pupa_gate_a20): Don't export, because turning off Gate A20 in a module is too dangerous. * include/pupa/loader.h (pupa_os_area_addr): Declared. (pupa_os_area_size): Likewise. (pupa_loader_set): Remove the first argument. Loader doesn't manage modules or initrd any longer. (pupa_loader_load_module): Removed. * conf/i386-pc.rmk (pkgdata_MODULES): Added linux.mod. (linux_mod_SOURCES): New variable. (linux_mod_CFLAGS): Likewise.
2003-01-17 02:52:05 +00:00
pupa_rescue_cmd_linux (int argc, char *argv[])
{
pupa_file_t file = 0;
struct linux_kernel_header lh;
pupa_uint8_t setup_sects;
pupa_size_t real_size, prot_size;
int i;
char *dest;
pupa_dl_ref (my_mod);
if (argc == 0)
{
pupa_error (PUPA_ERR_BAD_ARGUMENT, "no kernel specified");
goto fail;
}
file = pupa_file_open (argv[0]);
if (! file)
goto fail;
if (pupa_file_size (file) > (pupa_ssize_t) pupa_os_area_size)
{
pupa_error (PUPA_ERR_OUT_OF_RANGE, "too big kernel");
goto fail;
}
if (pupa_file_read (file, (char *) &lh, sizeof (lh)) != sizeof (lh))
{
pupa_error (PUPA_ERR_READ_ERROR, "cannot read the linux header");
goto fail;
}
if (lh.boot_flag != pupa_cpu_to_le16 (0xaa55))
{
pupa_error (PUPA_ERR_BAD_OS, "invalid magic number");
goto fail;
}
if (lh.setup_sects > PUPA_LINUX_MAX_SETUP_SECTS)
{
pupa_error (PUPA_ERR_BAD_OS, "too many setup sectors");
goto fail;
}
big_linux = 0;
setup_sects = lh.setup_sects;
linux_mem_size = 0;
if (lh.header == pupa_cpu_to_le32 (PUPA_LINUX_MAGIC_SIGNATURE)
&& pupa_le_to_cpu16 (lh.version) >= 0x0200)
{
big_linux = (lh.loadflags & PUPA_LINUX_FLAG_BIG_KERNEL);
lh.type_of_loader = PUPA_LINUX_BOOT_LOADER_TYPE;
/* Put the real mode part at as a high location as possible. */
pupa_linux_real_addr = (char *) (pupa_lower_mem
- PUPA_LINUX_SETUP_MOVE_SIZE);
/* But it must not exceed the traditional area. */
if (pupa_linux_real_addr > (char *) PUPA_LINUX_OLD_REAL_MODE_ADDR)
pupa_linux_real_addr = (char *) PUPA_LINUX_OLD_REAL_MODE_ADDR;
if (pupa_le_to_cpu16 (lh.version) >= 0x0201)
{
lh.heap_end_ptr = pupa_cpu_to_le16 (PUPA_LINUX_HEAP_END_OFFSET);
lh.loadflags |= PUPA_LINUX_FLAG_CAN_USE_HEAP;
}
if (pupa_le_to_cpu16 (lh.version) >= 0x0202)
lh.cmd_line_ptr = pupa_linux_real_addr + PUPA_LINUX_CL_OFFSET;
else
{
lh.cl_magic = pupa_cpu_to_le16 (PUPA_LINUX_CL_MAGIC);
lh.cl_offset = pupa_cpu_to_le16 (PUPA_LINUX_CL_OFFSET);
lh.setup_move_size = pupa_cpu_to_le16 (PUPA_LINUX_SETUP_MOVE_SIZE);
}
}
else
{
/* Your kernel is quite old... */
lh.cl_magic = pupa_cpu_to_le16 (PUPA_LINUX_CL_MAGIC);
lh.cl_offset = pupa_cpu_to_le16 (PUPA_LINUX_CL_OFFSET);
setup_sects = PUPA_LINUX_DEFAULT_SETUP_SECTS;
pupa_linux_real_addr = (char *) PUPA_LINUX_OLD_REAL_MODE_ADDR;
}
/* If SETUP_SECTS is not set, set it to the default (4). */
if (! setup_sects)
setup_sects = PUPA_LINUX_DEFAULT_SETUP_SECTS;
real_size = setup_sects << PUPA_DISK_SECTOR_BITS;
prot_size = pupa_file_size (file) - real_size - PUPA_DISK_SECTOR_SIZE;
pupa_linux_tmp_addr = (char *) PUPA_LINUX_BZIMAGE_ADDR + prot_size;
if (! big_linux
&& prot_size > (pupa_size_t) (pupa_linux_real_addr
- (char *) PUPA_LINUX_ZIMAGE_ADDR))
{
pupa_error (PUPA_ERR_BAD_OS, "too big zImage, use bzImage instead");
goto fail;
}
if (pupa_linux_real_addr + PUPA_LINUX_SETUP_MOVE_SIZE
> (char *) pupa_lower_mem)
{
pupa_error (PUPA_ERR_OUT_OF_RANGE, "too small lower memory");
goto fail;
}
pupa_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
big_linux ? "bzImage" : "zImage", real_size, prot_size);
for (i = 1; i < argc; i++)
if (pupa_memcmp (argv[i], "vga=", 4) == 0)
{
/* Video mode selection support. */
pupa_uint16_t vid_mode;
char *val = argv[i] + 4;
if (pupa_strcmp (val, "normal") == 0)
vid_mode = PUPA_LINUX_VID_MODE_NORMAL;
else if (pupa_strcmp (val, "ext") == 0)
vid_mode = PUPA_LINUX_VID_MODE_EXTENDED;
else if (pupa_strcmp (val, "ask") == 0)
vid_mode = PUPA_LINUX_VID_MODE_ASK;
else
vid_mode = (pupa_uint16_t) pupa_strtoul (val, 0, 0);
if (pupa_errno)
goto fail;
lh.vid_mode = pupa_cpu_to_le16 (vid_mode);
}
else if (pupa_memcmp (argv[i], "mem=", 4) == 0)
{
char *val = argv[i] + 4;
linux_mem_size = pupa_strtoul (val, &val, 0);
if (pupa_errno)
{
pupa_errno = PUPA_ERR_NONE;
linux_mem_size = 0;
}
else
{
int shift = 0;
switch (pupa_tolower (val[0]))
{
case 'g':
shift += 10;
case 'm':
shift += 10;
case 'k':
shift += 10;
default:
break;
}
/* Check an overflow. */
if (linux_mem_size > (~0UL >> shift))
linux_mem_size = 0;
else
linux_mem_size <<= shift;
}
}
/* Put the real mode code at the temporary address. */
pupa_memmove (pupa_linux_tmp_addr, &lh, sizeof (lh));
pupa_file_read (file, pupa_linux_tmp_addr + sizeof (lh),
real_size + PUPA_DISK_SECTOR_SIZE - sizeof (lh));
if (lh.header != pupa_cpu_to_le32 (PUPA_LINUX_MAGIC_SIGNATURE)
|| pupa_le_to_cpu16 (lh.version) < 0x0200)
/* Clear the heap space. */
pupa_memset (pupa_linux_tmp_addr
+ ((setup_sects + 1) << PUPA_DISK_SECTOR_BITS),
0,
((PUPA_LINUX_MAX_SETUP_SECTS - setup_sects - 1)
<< PUPA_DISK_SECTOR_BITS));
/* Copy kernel parameters. */
for (i = 1, dest = pupa_linux_tmp_addr + PUPA_LINUX_CL_OFFSET;
i < argc
&& dest + pupa_strlen (argv[i]) < (pupa_linux_tmp_addr
+ PUPA_LINUX_CL_END_OFFSET);
i++, *dest++ = ' ')
{
pupa_strcpy (dest, argv[i]);
dest += pupa_strlen (argv[i]);
}
if (i != 1)
dest--;
*dest = '\0';
pupa_file_read (file, (char *) PUPA_LINUX_BZIMAGE_ADDR, prot_size);
if (pupa_errno == PUPA_ERR_NONE)
{
pupa_linux_prot_size = prot_size;
pupa_loader_set (pupa_linux_boot, pupa_linux_unload);
loaded = 1;
}
fail:
if (file)
pupa_file_close (file);
if (pupa_errno != PUPA_ERR_NONE)
{
pupa_dl_unref (my_mod);
loaded = 0;
}
}
2003-01-20 Yoshinori K. Okuji <okuji@enbug.org> * include/pupa/normal.h: New file. * include/pupa/setjmp.h: Likewise. * include/pupa/i386/setjmp.h: Likewise. * normal/cmdline.c: Likewise. * normal/command.c: Likewise. * normal/main.c: Likewise. * normal/menu.c: Likewise. * normal/i386/setjmp.S: Likewise. * loader/i386/pc/linux.c (pupa_rescue_cmd_linux): Made global. (pupa_rescue_cmd_initrd): Likewise. * loader/i386/pc/chainloader.c (pupa_rescue_cmd_chainloader): Likewise. * kern/i386/pc/startup.S (translation_table): New variable. (translate_keycode): New function. (pupa_console_getkey): Call translate_keycode. * kern/rescue.c (attempt_normal_mode): New function. (pupa_enter_rescue_mode): Attempt to execute the normal mode. If it failed, print a message. * kern/mm.c (pupa_real_malloc): Print more information when a free magic is broken. (pupa_free): If the first free header is not free actually, set it to P. * kern/main.c (pupa_load_normal_mode): Just load the module "normal". (pupa_main): Don't print the message "Entering into rescue mode..." here. * include/pupa/i386/pc/loader.h (pupa_rescue_cmd_initrd): Declared. (pupa_rescue_cmd_initrd): Likewise. (pupa_rescue_cmd_initrd): Likewise. * include/pupa/symbol.h (FUNCTION): Specify the type. (VARIABLE): Likewise. * include/pupa/err.h (pupa_err_t): Added PUPA_ERR_UNKNOWN_COMMAND. * include/pupa/dl.h (pupa_dl_set_prefix): Exported. (pupa_dl_get_prefix): Likewise. * conf/i386-pc.rmk (pkgdata_MODULES): Added normal.mod. Added _chain.mod and _linux.mod instead of chain.mod and linux.mod. (chain_mod_SOURCES): Renamed to ... (_chain_mod_SOURCES): ... this. (chain_mod_CFLAGS): Renamed to ... (_chain_mod_CFLAGS): ... this. (linux_mod_SOURCES): Renamed to ... (_linux_mod_SOURCES): ... this. (linux_mod_CFLAGS): Renamed to ... (_linux_mod_CFLAGS): ... this. (normal_mod_SOURCES): New variable. (normal_mod_CFLAGS): Likewise. (normal_mod_ASFLAGS): Likewise. 2003-01-18 Yoshinori K. Okuji <okuji@enbug.org> * kern/rescue.c (pupa_rescue_cmd_rmmod): Call pupa_dl_unload, if possible. * kern/dl.c (pupa_dl_ref): Refer dependending modules recursively. (pupa_dl_unref): Unrefer depending modules recursively. Don't call pupa_dl_unload implicitly, because PUPA can crash if a module is unloaded before one depending on that module is unloaded. (pupa_dl_unload): Unload depending modules explicitly, if possible.
2003-01-20 04:13:46 +00:00
void
2003-01-17 Yoshinori K. Okuji <okuji@enbug.org> * include/pupa/i386/pc/linux.h: New file. * loader/i386/pc/linux.c: Likewise. * loader/i386/pc/chainloader.c (pupa_chainloader_boot_sector): Removed. (pupa_chainloader_unload): Return PUPA_ERR_NONE. (pupa_rescue_cmd_chainloader): Read the image to 0x7C00 instead of PUPA_CHAINLOADER_BOOT_SECTOR. * kern/i386/pc/startup.S: Include pupa/machine/linux.h. (pupa_linux_prot_size): New variable. (pupa_linux_tmp_addr): Likewise. (pupa_linux_real_addr): Likewise. (pupa_linux_boot_zimage): New function. (pupa_linux_boot_bzimage): Likewise. * kern/i386/pc/init.c (struct mem_region): New structure. (MAX_REGIONS): New macro. (mem_regions): New variable. (num_regions): Likewise. (pupa_os_area_addr): Likewise. (pupa_os_area_size): Likewise. (pupa_lower_mem): Likewise. (pupa_upper_mem): Likewise. (add_mem_region): New function. (compact_mem_regions): Likewise. (pupa_machine_init): Set PUPA_LOWER_MEM and PUPA_UPPER_MEM to the size of the conventional memory and that of so-called upper memory (before the first memory hole). Instead of adding each found region to free memory, use add_mem_region and add them after removing overlaps. Also, add only 1/4 of the upper memory to free memory. The rest is used for loading OS images. Maybe this is ad hoc, but this makes it much easier to relocate OS images when booting. * kern/rescue.c (pupa_rescue_cmd_module): Removed. (pupa_enter_rescue_mode): Don't register initrd and module. * kern/mm.c: Include pupa/dl.h. * kern/main.c: Include pupa/file.h and pupa/device.h. * kern/loader.c (pupa_loader_load_module_func): Removed. (pupa_loader_load_module): Likewise. * kern/dl.c (pupa_dl_load): Use the suffix ``.mod'' instead of ``.o''. * include/pupa/i386/pc/loader.h (pupa_linux_prot_size): Declared. (pupa_linux_tmp_addr): Likewise. (pupa_linux_real_addr): Likewise. (pupa_linux_boot_zimage): Likewise. (pupa_linux_boot_bzimage): Likewise. * include/pupa/i386/pc/init.h (pupa_lower_mem): Declared. (pupa_upper_mem): Likewise. (pupa_gate_a20): Don't export, because turning off Gate A20 in a module is too dangerous. * include/pupa/loader.h (pupa_os_area_addr): Declared. (pupa_os_area_size): Likewise. (pupa_loader_set): Remove the first argument. Loader doesn't manage modules or initrd any longer. (pupa_loader_load_module): Removed. * conf/i386-pc.rmk (pkgdata_MODULES): Added linux.mod. (linux_mod_SOURCES): New variable. (linux_mod_CFLAGS): Likewise.
2003-01-17 02:52:05 +00:00
pupa_rescue_cmd_initrd (int argc, char *argv[])
{
pupa_error (PUPA_ERR_NOT_IMPLEMENTED_YET, "not implemented yet");
}
PUPA_MOD_INIT
{
pupa_rescue_register_command ("linux",
pupa_rescue_cmd_linux,
"load linux");
pupa_rescue_register_command ("initrd",
pupa_rescue_cmd_initrd,
"load initrd");
my_mod = mod;
}
PUPA_MOD_FINI
{
pupa_rescue_unregister_command ("linux");
pupa_rescue_unregister_command ("initrd");
}