Move chainloader_real_boot out of the kernel
This commit is contained in:
parent
766f7d0809
commit
db1326f5fb
11 changed files with 148 additions and 69 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
*
|
||||
|
|
|
@ -49,6 +49,7 @@ grub_reboot (void)
|
|||
state.sp = 0;
|
||||
state.cs = segment;
|
||||
state.ip = 0;
|
||||
state.a20 = 0;
|
||||
|
||||
grub_stop_floppy ();
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue