Move chainloader_real_boot out of the kernel

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-10-21 00:16:59 +02:00
parent 766f7d0809
commit db1326f5fb
11 changed files with 148 additions and 69 deletions

View file

@ -83,7 +83,6 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h
if COND_i386_pc
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h

View file

@ -463,31 +463,6 @@ FUNCTION(grub_exit)
ljmp $0xf000, $0xfff0
.code32
/*
* void grub_chainloader_real_boot (int drive, void *part_addr)
*
* This starts another boot loader.
*/
FUNCTION(grub_chainloader_real_boot)
pushl %edx
pushl %eax
/* Turn off Gate A20 */
xorl %eax, %eax
call grub_gate_a20
/* set up to pass boot drive */
popl %edx
/* ESI must point to a partition table entry */
popl %esi
call prot_to_real
.code16
ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
.code32
/*
* void grub_console_putchar (int c)
*

View file

@ -49,6 +49,7 @@ grub_reboot (void)
state.sp = 0;
state.cs = segment;
state.ip = 0;
state.a20 = 0;
grub_stop_floppy ();

View file

@ -51,6 +51,9 @@ extern grub_uint16_t grub_relocator16_ss;
extern grub_uint16_t grub_relocator16_sp;
extern grub_uint32_t grub_relocator16_edx;
extern grub_uint32_t grub_relocator16_ebx;
extern grub_uint32_t grub_relocator16_esi;
extern grub_uint16_t grub_relocator16_keep_a20_enabled;
extern grub_uint8_t grub_relocator32_start;
extern grub_uint8_t grub_relocator32_end;
@ -195,7 +198,8 @@ grub_relocator16_boot (struct grub_relocator *rel,
void *relst;
grub_relocator_chunk_t ch;
err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
/* Put it higher than the byte it checks for A20 check. */
err = grub_relocator_alloc_chunk_align (rel, &ch, 0x8010,
0xa0000 - RELOCATOR_SIZEOF (16),
RELOCATOR_SIZEOF (16), 16,
GRUB_RELOCATOR_PREFERENCE_NONE);
@ -215,6 +219,9 @@ grub_relocator16_boot (struct grub_relocator *rel,
grub_relocator16_ebx = state.ebx;
grub_relocator16_edx = state.edx;
grub_relocator16_esi = state.esi;
grub_relocator16_keep_a20_enabled = state.a20;
grub_memmove (get_virtual_current_address (ch), &grub_relocator16_start,
RELOCATOR_SIZEOF (16));

View file

@ -93,6 +93,85 @@ LOCAL(segment):
.word 0
LOCAL(cont3):
/* movw imm16, %ax. */
.byte 0xb8
VARIABLE(grub_relocator16_keep_a20_enabled)
.word 0
test %ax, %ax
jnz LOCAL(gate_a20_done)
/* first of all, test if already in a good state */
call LOCAL(gate_a20_check_state)
testb %al, %al
jz LOCAL(gate_a20_done)
/* second, try a BIOS call */
movw $0x2400, %ax
int $0x15
call LOCAL(gate_a20_check_state)
testb %al, %al
jz LOCAL(gate_a20_done)
/*
* In macbook, the keyboard test would hang the machine, so we move
* this forward.
*/
/* fourth, try the system control port A */
inb $0x92
andb $(~0x03), %al
outb $0x92
/* When turning off Gate A20, do not check the state strictly,
because a failure is not fatal usually, and Gate A20 is always
on some modern machines. */
jmp LOCAL(gate_a20_done)
LOCAL(gate_a20_check_state):
/* iterate the checking for a while */
movw $100, %cx
1:
call 3f
testb %al, %al
jz 2f
loop 1b
2:
ret
3:
xorw %ax, %ax
movw %ax, %ds
decw %ax
movw %ax, %es
xorw %ax, %ax
movw $0x8000, %ax
/* compare the byte at ADDR with that at 0x100000 + ADDR */
movw %ax, %si
addw $0x10, %ax
movw %ax, %di
/* save the original byte in DL */
movb %ds:(%si), %dl
movb %es:(%di), %al
/* try to set one less value at ADDR */
movb %al, %dh
decb %dh
movb %dh, %ds:(%si)
/* serialize */
outb %al, $0x80
outb %al, $0x80
/* obtain the value at 0x100000 + ADDR in CH */
movb %es:(%di), %dh
/* this result is 1 if A20 is on or 0 if it is off */
subb %dh, %al
xorb $1, %al
/* restore the original */
movb %dl, %es:(%di)
ret
LOCAL(gate_a20_done):
/* we are in real mode now
* set up the real mode segment registers : DS, SS, ES
*/
@ -132,6 +211,12 @@ VARIABLE(grub_relocator16_sp)
.word 0
movzwl %ax, %esp
/* movw imm32, %eax. */
.byte 0x66, 0xb8
VARIABLE(grub_relocator16_esi)
.long 0
movl %eax, %esi
/* movw imm32, %edx. */
.byte 0x66, 0xba
VARIABLE(grub_relocator16_edx)

View file

@ -18,7 +18,6 @@
*/
#include <grub/loader.h>
#include <grub/machine/loader.h>
#include <grub/machine/chainloader.h>
#include <grub/machine/memory.h>
#include <grub/file.h>
@ -39,12 +38,14 @@
#include <grub/mm.h>
#include <grub/fat.h>
#include <grub/ntfs.h>
#include <grub/i386/relocator.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
static int boot_drive;
static void *boot_part_addr;
static grub_addr_t boot_part_addr;
static struct grub_relocator *rel;
typedef enum
{
@ -55,16 +56,29 @@ typedef enum
static grub_err_t
grub_chainloader_boot (void)
{
struct grub_relocator16_state state = {
.edx = boot_drive,
.esi = boot_part_addr,
.ds = 0,
.es = 0,
.fs = 0,
.gs = 0,
.ss = 0,
.cs = 0,
.sp = GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR,
.ip = GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR,
.a20 = 0
};
grub_video_set_mode ("text", 0, 0);
grub_chainloader_real_boot (boot_drive, boot_part_addr);
/* Never reach here. */
return GRUB_ERR_NONE;
return grub_relocator16_boot (rel, state);
}
static grub_err_t
grub_chainloader_unload (void)
{
grub_relocator_unload (rel);
rel = NULL;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
@ -133,7 +147,12 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
grub_uint16_t signature;
grub_device_t dev;
int drive = -1;
void *part_addr = 0;
grub_addr_t part_addr = 0;
grub_uint8_t *bs, *ptable;
rel = grub_relocator_new ();
if (!rel)
goto fail;
grub_dl_ref (my_mod);
@ -142,8 +161,25 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
if (! file)
goto fail;
{
grub_relocator_chunk_t ch;
grub_err_t err;
err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00,
GRUB_DISK_SECTOR_SIZE);
if (err)
goto fail;
bs = get_virtual_current_address (ch);
err = grub_relocator_alloc_chunk_addr (rel, &ch,
GRUB_MEMORY_MACHINE_PART_TABLE_ADDR,
64);
if (err)
goto fail;
ptable = get_virtual_current_address (ch);
}
/* Read the first block. */
if (grub_file_read (file, (void *) 0x7C00, GRUB_DISK_SECTOR_SIZE)
if (grub_file_read (file, bs, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
{
if (grub_errno == GRUB_ERR_NONE)
@ -153,7 +189,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
}
/* Check the signature. */
signature = *((grub_uint16_t *) (0x7C00 + GRUB_DISK_SECTOR_SIZE - 2));
signature = *((grub_uint16_t *) (bs + GRUB_DISK_SECTOR_SIZE - 2));
if (signature != grub_le_to_cpu16 (0xaa55)
&& ! (flags & GRUB_CHAINLOADER_FORCE))
{
@ -177,10 +213,9 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
if (p && grub_strcmp (p->partmap->name, "msdos") == 0)
{
disk->partition = p->parent;
grub_disk_read (disk, p->offset, 446, 64,
(void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+ (p->index << 4));
grub_disk_read (disk, p->offset, 446, 64, ptable);
part_addr = (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+ (p->index << 4));
disk->partition = p;
}
}

View file

@ -56,7 +56,8 @@ grub_freedos_boot (void)
.ss = GRUB_FREEDOS_STACK_SEGMENT,
.sp = GRUB_FREEDOS_STACK_POINTER,
.ebx = ebx,
.edx = 0
.edx = 0,
.a20 = 1
};
grub_video_set_mode ("text", 0, 0);

View file

@ -18,7 +18,6 @@
*/
#include <grub/loader.h>
#include <grub/machine/loader.h>
#include <grub/file.h>
#include <grub/err.h>
#include <grub/device.h>
@ -61,6 +60,7 @@ grub_linux16_boot (void)
state.sp = GRUB_LINUX_SETUP_STACK;
state.cs = segment + 0x20;
state.ip = 0;
state.a20 = 1;
grub_video_set_mode ("text", 0, 0);

View file

@ -54,7 +54,8 @@ grub_ntldr_boot (void)
.gs = 0,
.ss = 0,
.sp = 0x7c00,
.edx = edx
.edx = edx,
.a20 = 1
};
grub_video_set_mode ("text", 0, 0);

View file

@ -1,27 +0,0 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2007 Free Software Foundation, Inc.
*
* GRUB 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 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_LOADER_MACHINE_HEADER
#define GRUB_LOADER_MACHINE_HEADER 1
#include <grub/symbol.h>
/* This is an asm part of the chainloader. */
void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn));
#endif /* ! GRUB_LOADER_MACHINE_HEADER */

View file

@ -48,6 +48,8 @@ struct grub_relocator16_state
grub_uint16_t ip;
grub_uint32_t ebx;
grub_uint32_t edx;
grub_uint32_t esi;
int a20;
};
struct grub_relocator64_state