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
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)
*
state.sp = 0;
state.cs = segment;
state.ip = 0;
+ state.a20 = 0;
grub_stop_floppy ();
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;
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);
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));
.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
*/
.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)
*/
#include <grub/loader.h>
-#include <grub/machine/loader.h>
#include <grub/machine/chainloader.h>
#include <grub/machine/memory.h>
#include <grub/file.h>
#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
{
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;
}
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);
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)
}
/* 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))
{
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;
}
}
.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);
*/
#include <grub/loader.h>
-#include <grub/machine/loader.h>
#include <grub/file.h>
#include <grub/err.h>
#include <grub/device.h>
state.sp = GRUB_LINUX_SETUP_STACK;
state.cs = segment + 0x20;
state.ip = 0;
+ state.a20 = 1;
grub_video_set_mode ("text", 0, 0);
.gs = 0,
.ss = 0,
.sp = 0x7c00,
- .edx = edx
+ .edx = edx,
+ .a20 = 1
};
grub_video_set_mode ("text", 0, 0);
+++ /dev/null
-/*
- * 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 */
grub_uint16_t ip;
grub_uint32_t ebx;
grub_uint32_t edx;
+ grub_uint32_t esi;
+ int a20;
};
struct grub_relocator64_state