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.
This commit is contained in:
okuji 2003-01-17 02:52:05 +00:00
parent a13f92373c
commit c04da07444
17 changed files with 705 additions and 61 deletions

View file

@ -1,3 +1,74 @@
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-07 Yoshinori K. Okuji <okuji@enbug.org>
* util/i386/pc/pupa-setup.c (setup): Convert the endianness of

2
NEWS
View file

@ -13,6 +13,8 @@ New in 0.7:
* New commands, "prefix", "insmod", "rmmod" and "lsmod" are added into
the rescue mode to manipulate PUPA modules.
* Linux support is added. Initrd is not support yet.
New in 0.6 - 2002-12-27, Yoshinori K. Okuji:

View file

@ -393,7 +393,7 @@ genmoddep-util_genmoddep.d: util/genmoddep.c
# Modules.
pkgdata_MODULES = chain.mod fat.mod
pkgdata_MODULES = chain.mod fat.mod linux.mod
# For chain.mod.
chain_mod_SOURCES = loader/i386/pc/chainloader.c
@ -472,6 +472,45 @@ fat_mod-fs_fat.d: fs/fat.c
-include fat_mod-fs_fat.d
fat_mod_CFLAGS = $(COMMON_CFLAGS)
# For linux.mod.
linux_mod_SOURCES = loader/i386/pc/linux.c
CLEANFILES += linux.mod mod-linux.o mod-linux.c pre-linux.o linux_mod-loader_i386_pc_linux.o def-linux.lst und-linux.lst
MOSTLYCLEANFILES += linux_mod-loader_i386_pc_linux.d
DEFSYMFILES += def-linux.lst
UNDSYMFILES += und-linux.lst
linux.mod: pre-linux.o mod-linux.o
-rm -f $@
$(LD) -r -o $@ $^
$(STRIP) --strip-unneeded -K pupa_mod_init -K pupa_mod_fini -R .note -R .comment $@
pre-linux.o: linux_mod-loader_i386_pc_linux.o
-rm -f $@
$(LD) -r -o $@ $^
mod-linux.o: mod-linux.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(linux_mod_CFLAGS) -c -o $@ $<
mod-linux.c: moddep.lst genmodsrc.sh
sh $(srcdir)/genmodsrc.sh 'linux' $< > $@ || (rm -f $@; exit 1)
def-linux.lst: pre-linux.o
$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 linux/' > $@
und-linux.lst: pre-linux.o
echo 'linux' > $@
$(NM) -u -P -p $< >> $@
linux_mod-loader_i386_pc_linux.o: loader/i386/pc/linux.c
$(CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(CPPFLAGS) $(CFLAGS) $(linux_mod_CFLAGS) -c -o $@ $<
linux_mod-loader_i386_pc_linux.d: loader/i386/pc/linux.c
set -e; $(CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(CPPFLAGS) $(CFLAGS) $(linux_mod_CFLAGS) -M $< | sed 's,linux\.o[ :]*,linux_mod-loader_i386_pc_linux.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
-include linux_mod-loader_i386_pc_linux.d
linux_mod_CFLAGS = $(COMMON_CFLAGS)
CLEANFILES += moddep.lst
pkgdata_DATA += moddep.lst
moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep

View file

@ -60,7 +60,7 @@ pupa_setup_SOURCES = util/i386/pc/pupa-setup.c util/i386/pc/biosdisk.c \
genmoddep_SOURCES = util/genmoddep.c
# Modules.
pkgdata_MODULES = chain.mod fat.mod
pkgdata_MODULES = chain.mod fat.mod linux.mod
# For chain.mod.
chain_mod_SOURCES = loader/i386/pc/chainloader.c
@ -69,3 +69,7 @@ chain_mod_CFLAGS = $(COMMON_CFLAGS)
# For fat.mod.
fat_mod_SOURCES = fs/fat.c
fat_mod_CFLAGS = $(COMMON_CFLAGS)
# For linux.mod.
linux_mod_SOURCES = loader/i386/pc/linux.c
linux_mod_CFLAGS = $(COMMON_CFLAGS)

View file

@ -23,6 +23,10 @@
#include <pupa/types.h>
#include <pupa/symbol.h>
/* FIXME: Should these be declared in memory.h? */
extern pupa_size_t EXPORT_VAR(pupa_lower_mem);
extern pupa_size_t EXPORT_VAR(pupa_upper_mem);
/* Get the memory size in KB. If EXTENDED is zero, return conventional
memory, otherwise return extended memory. */
pupa_uint16_t pupa_get_memsize (int extended);
@ -45,6 +49,6 @@ pupa_uint32_t pupa_get_mmap_entry (struct pupa_machine_mmap_entry *entry,
pupa_uint32_t cont);
/* Turn on/off Gate A20. */
void EXPORT_FUNC(pupa_gate_a20) (int on);
void pupa_gate_a20 (int on);
#endif /* ! PUPA_INIT_MACHINE_HEADER */

View file

@ -0,0 +1,85 @@
/*
* 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.
*/
#ifndef PUPA_LINUX_MACHINE_HEADER
#define PUPA_LINUX_MACHINE_HEADER 1
#define PUPA_LINUX_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */
#define PUPA_LINUX_DEFAULT_SETUP_SECTS 4
#define PUPA_LINUX_FLAG_CAN_USE_HEAP 0x80
#define PUPA_LINUX_INITRD_MAX_ADDRESS 0x38000000
#define PUPA_LINUX_MAX_SETUP_SECTS 64
#define PUPA_LINUX_BOOT_LOADER_TYPE 0x72
#define PUPA_LINUX_HEAP_END_OFFSET (0x9000 - 0x200)
#define PUPA_LINUX_BZIMAGE_ADDR 0x100000
#define PUPA_LINUX_ZIMAGE_ADDR 0x10000
#define PUPA_LINUX_OLD_REAL_MODE_ADDR 0x90000
#define PUPA_LINUX_SETUP_STACK 0x9000
#define PUPA_LINUX_FLAG_BIG_KERNEL 0x1
/* Linux's video mode selection support. Actually I hate it! */
#define PUPA_LINUX_VID_MODE_NORMAL 0xFFFF
#define PUPA_LINUX_VID_MODE_EXTENDED 0xFFFE
#define PUPA_LINUX_VID_MODE_ASK 0xFFFD
#define PUPA_LINUX_CL_OFFSET 0x9000
#define PUPA_LINUX_CL_END_OFFSET 0x90FF
#define PUPA_LINUX_SETUP_MOVE_SIZE 0x9100
#define PUPA_LINUX_CL_MAGIC 0xA33F
#ifndef ASM_FILE
/* For the Linux/i386 boot protocol version 2.03. */
struct linux_kernel_header
{
pupa_uint8_t code1[0x0020];
pupa_uint16_t cl_magic; /* Magic number 0xA33F */
pupa_uint16_t cl_offset; /* The offset of command line */
pupa_uint8_t code2[0x01F1 - 0x0020 - 2 - 2];
pupa_uint8_t setup_sects; /* The size of the setup in sectors */
pupa_uint16_t root_flags; /* If the root is mounted readonly */
pupa_uint16_t syssize; /* obsolete */
pupa_uint16_t swap_dev; /* obsolete */
pupa_uint16_t ram_size; /* obsolete */
pupa_uint16_t vid_mode; /* Video mode control */
pupa_uint16_t root_dev; /* Default root device number */
pupa_uint16_t boot_flag; /* 0xAA55 magic number */
pupa_uint16_t jump; /* Jump instruction */
pupa_uint32_t header; /* Magic signature "HdrS" */
pupa_uint16_t version; /* Boot protocol version supported */
pupa_uint32_t realmode_swtch; /* Boot loader hook */
pupa_uint32_t start_sys; /* Points to kernel version string */
pupa_uint8_t type_of_loader; /* Boot loader identifier */
pupa_uint8_t loadflags; /* Boot protocol option flags */
pupa_uint16_t setup_move_size; /* Move to high memory size */
pupa_uint32_t code32_start; /* Boot loader hook */
pupa_uint32_t ramdisk_image; /* initrd load address */
pupa_uint32_t ramdisk_size; /* initrd size */
pupa_uint32_t bootsect_kludge; /* obsolete */
pupa_uint16_t heap_end_ptr; /* Free memory after setup end */
pupa_uint16_t pad1; /* Unused */
char *cmd_line_ptr; /* Points to the kernel command line */
} __attribute__ ((packed));
#endif /* ! ASM_FILE */
#endif /* ! PUPA_LINUX_MACHINE_HEADER */

View file

@ -23,6 +23,13 @@
#include <pupa/types.h>
#include <pupa/symbol.h>
extern pupa_uint32_t EXPORT_VAR(pupa_linux_prot_size);
extern char *EXPORT_VAR(pupa_linux_tmp_addr);
extern char *EXPORT_VAR(pupa_linux_real_addr);
void EXPORT_FUNC(pupa_linux_boot_zimage) (void) __attribute__ ((noreturn));
void EXPORT_FUNC(pupa_linux_boot_bzimage) (void) __attribute__ ((noreturn));
/* This is an asm part of the chainloader. */
void EXPORT_FUNC(pupa_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn));

View file

@ -26,12 +26,12 @@
#include <pupa/err.h>
#include <pupa/types.h>
void EXPORT_FUNC(pupa_loader_set) (pupa_err_t (*load_module) (int argc,
char *argv[]),
pupa_err_t (*boot) (void),
extern pupa_addr_t EXPORT_VAR(pupa_os_area_addr);
extern pupa_size_t EXPORT_VAR(pupa_os_area_size);
void EXPORT_FUNC(pupa_loader_set) (pupa_err_t (*boot) (void),
pupa_err_t (*unload) (void));
pupa_err_t EXPORT_FUNC(pupa_loader_load_module) (int argc, char *argv[]);
pupa_err_t EXPORT_FUNC(pupa_loader_boot) (void);
#endif /* ! PUPA_LOADER_HEADER */

View file

@ -569,11 +569,11 @@ pupa_dl_load (const char *name)
pupa_fatal ("module dir is not initialized yet");
filename = (char *) pupa_malloc (pupa_strlen (pupa_dl_dir) + 1
+ pupa_strlen (name) + 3);
+ pupa_strlen (name) + 4 + 1);
if (! filename)
return 0;
pupa_sprintf (filename, "%s/%s.o", pupa_dl_dir, name);
pupa_sprintf (filename, "%s/%s.mod", pupa_dl_dir, name);
mod = pupa_dl_load_file (filename);
pupa_free (filename);

View file

@ -28,6 +28,22 @@
#include <pupa/err.h>
#include <pupa/dl.h>
#include <pupa/misc.h>
#include <pupa/loader.h>
struct mem_region
{
pupa_addr_t addr;
pupa_size_t size;
};
#define MAX_REGIONS 32
static struct mem_region mem_regions[MAX_REGIONS];
static int num_regions;
pupa_addr_t pupa_os_area_addr;
pupa_size_t pupa_os_area_size;
pupa_size_t pupa_lower_mem, pupa_upper_mem;
static char *
make_install_device (void)
@ -51,32 +67,79 @@ make_install_device (void)
return pupa_prefix;
}
/* Add a memory region. */
static void
add_mem_region (pupa_addr_t addr, pupa_size_t size)
{
if (num_regions == MAX_REGIONS)
/* Ignore. */
return;
mem_regions[num_regions].addr = addr;
mem_regions[num_regions].size = size;
num_regions++;
}
/* Compact memory regions. */
static void
compact_mem_regions (void)
{
int i, j;
/* Sort them. */
for (i = 0; i < num_regions - 1; i++)
for (j = i + 1; j < num_regions; j++)
if (mem_regions[i].addr > mem_regions[j].addr)
{
struct mem_region tmp = mem_regions[i];
mem_regions[i] = mem_regions[j];
mem_regions[j] = tmp;
}
/* Merge overlaps. */
for (i = 0; i < num_regions - 1; i++)
if (mem_regions[i].addr + mem_regions[i].size >= mem_regions[i + 1].addr)
{
j = i + 1;
if (mem_regions[i].addr + mem_regions[i].size
< mem_regions[j].addr + mem_regions[j].size)
mem_regions[i].size = (mem_regions[j].addr + mem_regions[j].size
- mem_regions[i].addr);
pupa_memmove (mem_regions + j, mem_regions + j + 1,
(num_regions - j - 1) * sizeof (struct mem_region));
i--;
}
}
void
pupa_machine_init (void)
{
pupa_uint32_t cont;
struct pupa_machine_mmap_entry *entry
= (struct pupa_machine_mmap_entry *) PUPA_MEMORY_MACHINE_SCRATCH_ADDR;
pupa_size_t lower_mem = (pupa_get_memsize (0) << 10);
pupa_addr_t end_addr = pupa_get_end_addr ();
int i;
/* Initialize the console as early as possible. */
pupa_console_init ();
pupa_lower_mem = pupa_get_memsize (0) << 10;
/* Sanity check. */
if (lower_mem < PUPA_MEMORY_MACHINE_RESERVED_END)
if (pupa_lower_mem < PUPA_MEMORY_MACHINE_RESERVED_END)
pupa_fatal ("too small memory");
/* Turn on Gate A20 to access >1MB. */
pupa_gate_a20 (1);
/* Add the lower memory into free memory. */
if (lower_mem >= PUPA_MEMORY_MACHINE_RESERVED_END)
pupa_mm_init_region ((void *) PUPA_MEMORY_MACHINE_RESERVED_END,
lower_mem - PUPA_MEMORY_MACHINE_RESERVED_END);
if (pupa_lower_mem >= PUPA_MEMORY_MACHINE_RESERVED_END)
add_mem_region (PUPA_MEMORY_MACHINE_RESERVED_END,
pupa_lower_mem - PUPA_MEMORY_MACHINE_RESERVED_END);
pupa_mm_init_region ((void *) end_addr,
PUPA_MEMORY_MACHINE_RESERVED_START - end_addr);
add_mem_region (end_addr, PUPA_MEMORY_MACHINE_RESERVED_START - end_addr);
/* Check if pupa_get_mmap_entry works. */
cont = pupa_get_mmap_entry (entry, 0);
@ -104,7 +167,7 @@ pupa_machine_init (void)
len = ((addr + entry->len > 0xFFFFFFFF)
? 0xFFFFFFFF - addr
: (pupa_size_t) entry->len);
pupa_mm_init_region ((void *) addr, len);
add_mem_region (addr, len);
}
next:
@ -121,20 +184,39 @@ pupa_machine_init (void)
if (eisa_mmap)
{
if ((eisa_mmap & 0xFFFF) == 0x3C00)
pupa_mm_init_region ((void *) 0x100000,
(eisa_mmap << 16) + 0x100000 * 15);
add_mem_region (0x100000, (eisa_mmap << 16) + 0x100000 * 15);
else
{
pupa_mm_init_region ((void *) 0x100000,
(eisa_mmap & 0xFFFF) << 10);
pupa_mm_init_region ((void *) 0x1000000, eisa_mmap << 16);
add_mem_region (0x100000, (eisa_mmap & 0xFFFF) << 10);
add_mem_region (0x1000000, eisa_mmap << 16);
}
}
else
pupa_mm_init_region ((void *) 0x100000,
(pupa_size_t) pupa_get_memsize (1) << 10);
add_mem_region (0x100000, pupa_get_memsize (1) << 10);
}
compact_mem_regions ();
/* Add the memory regions to free memory, except for the region starting
from 1MB. This region is partially used for loading OS images.
For now, 1/4 of this is added to free memory. */
for (i = 0; i < num_regions; i++)
if (mem_regions[i].addr == 0x100000)
{
pupa_size_t quarter = mem_regions[i].size >> 2;
pupa_upper_mem = mem_regions[i].size;
pupa_os_area_addr = mem_regions[i].addr;
pupa_os_area_size = mem_regions[i].size - quarter;
pupa_mm_init_region ((void *) (pupa_os_area_addr + pupa_os_area_size),
quarter);
}
else
pupa_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size);
if (! pupa_os_area_addr)
pupa_fatal ("no upper memory");
/* The memory system was initialized, thus register built-in devices. */
pupa_biosdisk_init ();

View file

@ -49,7 +49,8 @@
#include <pupa/machine/boot.h>
#include <pupa/machine/memory.h>
#include <pupa/machine/console.h>
#include <pupa/machine/linux.h>
#define ABS(x) ((x) - EXT_C(start) + PUPA_BOOT_MACHINE_KERNEL_ADDR + 0x200)
.file "startup.S"
@ -282,6 +283,71 @@ FUNCTION(pupa_chainloader_real_boot)
.code32
/*
* void pupa_linux_boot_zimage (void)
*/
VARIABLE(pupa_linux_prot_size)
.long 0
VARIABLE(pupa_linux_tmp_addr)
.long 0
VARIABLE(pupa_linux_real_addr)
.long 0
FUNCTION(pupa_linux_boot_zimage)
/* copy the kernel */
movl EXT_C(pupa_linux_prot_size), %ecx
addl $3, %ecx
shrl $2, %ecx
movl $PUPA_LINUX_BZIMAGE_ADDR, %esi
movl $PUPA_LINUX_ZIMAGE_ADDR, %edi
cld
rep
movsl
FUNCTION(pupa_linux_boot_bzimage)
call EXT_C(pupa_dl_unload_all)
movl EXT_C(pupa_linux_real_addr), %ebx
/* copy the real mode code */
movl EXT_C(pupa_linux_tmp_addr), %esi
movl %ebx, %edi
movl $PUPA_LINUX_SETUP_MOVE_SIZE, %ecx
cld
rep
movsb
/* change %ebx to the segment address */
shrl $4, %ebx
movl %ebx, %eax
addl $0x20, %eax
movw %ax, linux_setup_seg
/* XXX new stack pointer in safe area for calling functions */
movl $0x4000, %esp
call EXT_C(pupa_stop_floppy)
/* final setup for linux boot */
call prot_to_real
.code16
cli
movw %bx, %ss
movw $PUPA_LINUX_SETUP_STACK, %sp
movw %bx, %ds
movw %bx, %es
movw %bx, %fs
movw %bx, %gs
/* ljmp */
.byte 0xea
.word 0
linux_setup_seg:
.word 0
.code32
/*
* These next two routines, "real_to_prot" and "prot_to_real" are structured
* in a very specific way. Be very careful when changing them.

View file

@ -22,40 +22,25 @@
#include <pupa/mm.h>
#include <pupa/err.h>
static pupa_err_t (*pupa_loader_load_module_func) (int argc, char *argv[]);
static pupa_err_t (*pupa_loader_boot_func) (void);
static pupa_err_t (*pupa_loader_unload_func) (void);
static int pupa_loader_loaded;
void
pupa_loader_set (pupa_err_t (*load_module) (int argc, char *argv[]),
pupa_err_t (*boot) (void),
pupa_loader_set (pupa_err_t (*boot) (void),
pupa_err_t (*unload) (void))
{
if (pupa_loader_loaded && pupa_loader_unload_func)
if (pupa_loader_unload_func () != PUPA_ERR_NONE)
return;
pupa_loader_load_module_func = load_module;
pupa_loader_boot_func = boot;
pupa_loader_unload_func = unload;
pupa_loader_loaded = 1;
}
pupa_err_t
pupa_loader_load_module (int argc, char *argv[])
{
if (! pupa_loader_loaded)
return pupa_error (PUPA_ERR_NO_KERNEL, "no loaded kernel");
if (! pupa_loader_load_module_func)
return pupa_error (PUPA_ERR_BAD_OS, "module not supported");
return pupa_loader_load_module_func (argc, argv);
}
pupa_err_t
pupa_loader_boot (void)
{

View file

@ -25,6 +25,8 @@
#include <pupa/dl.h>
#include <pupa/term.h>
#include <pupa/rescue.h>
#include <pupa/file.h>
#include <pupa/device.h>
/* Return the end of the core image. */
pupa_addr_t

View file

@ -24,6 +24,7 @@
#include <pupa/err.h>
#include <pupa/types.h>
#include <pupa/disk.h>
#include <pupa/dl.h>
/* Magic words. */
#define PUPA_MM_FREE_MAGIC 0x2d3c2808
@ -95,6 +96,10 @@ pupa_mm_init_region (void *addr, pupa_size_t size)
pupa_mm_header_t h;
pupa_mm_region_t r, *p, q;
#if 0
pupa_printf ("%s:%d: addr=%p, size=%u\n", __FILE__, __LINE__, addr, size);
#endif
/* If this region is too small, ignore it. */
if (size < PUPA_MM_ALIGN * 2)
return;

View file

@ -337,13 +337,6 @@ pupa_rescue_cmd_info (void)
}
#endif
/* (module|initrd) FILE [ARGS] */
static void
pupa_rescue_cmd_module (int argc, char *argv[])
{
pupa_loader_load_module (argc, argv);
}
/* root [DEVICE] */
static void
pupa_rescue_cmd_root (int argc, char *argv[])
@ -607,12 +600,8 @@ pupa_enter_rescue_mode (void)
"show the contents of a file");
pupa_rescue_register_command ("help", pupa_rescue_cmd_help,
"show this message");
pupa_rescue_register_command ("initrd", pupa_rescue_cmd_module,
"load an initrd");
pupa_rescue_register_command ("ls", pupa_rescue_cmd_ls,
"list devices or files");
pupa_rescue_register_command ("module", pupa_rescue_cmd_module,
"load an OS module");
pupa_rescue_register_command ("root", pupa_rescue_cmd_root,
"set the root device");
pupa_rescue_register_command ("dump", pupa_rescue_cmd_dump,

View file

@ -32,9 +32,6 @@
#include <pupa/rescue.h>
#include <pupa/dl.h>
/* Allocate space statically, because this is very small anyway. */
static char pupa_chainloader_boot_sector[PUPA_DISK_SECTOR_SIZE];
static pupa_dl_t my_mod;
static pupa_err_t
@ -81,6 +78,7 @@ static pupa_err_t
pupa_chainloader_unload (void)
{
pupa_dl_unref (my_mod);
return PUPA_ERR_NONE;
}
static void
@ -110,8 +108,8 @@ pupa_rescue_cmd_chainloader (int argc, char *argv[])
goto fail;
/* Read the first block. */
if (pupa_file_read (file, pupa_chainloader_boot_sector,
PUPA_DISK_SECTOR_SIZE) != PUPA_DISK_SECTOR_SIZE)
if (pupa_file_read (file, (char *) 0x7C00, PUPA_DISK_SECTOR_SIZE)
!= PUPA_DISK_SECTOR_SIZE)
{
if (pupa_errno == PUPA_ERR_NONE)
pupa_error (PUPA_ERR_BAD_OS, "too small");
@ -120,8 +118,7 @@ pupa_rescue_cmd_chainloader (int argc, char *argv[])
}
/* Check the signature. */
signature = *((pupa_uint16_t *) (pupa_chainloader_boot_sector
+ PUPA_DISK_SECTOR_SIZE - 2));
signature = *((pupa_uint16_t *) (0x7C00 + PUPA_DISK_SECTOR_SIZE - 2));
if (signature != pupa_le_to_cpu16 (0xaa55) && ! force)
{
pupa_error (PUPA_ERR_BAD_OS, "invalid signature");
@ -129,7 +126,7 @@ pupa_rescue_cmd_chainloader (int argc, char *argv[])
}
pupa_file_close (file);
pupa_loader_set (0, pupa_chainloader_boot, pupa_chainloader_unload);
pupa_loader_set (pupa_chainloader_boot, pupa_chainloader_unload);
return;
fail:

306
loader/i386/pc/linux.c Normal file
View file

@ -0,0 +1,306 @@
/* 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;
}
static void
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;
}
}
static void
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");
}