summaryrefslogtreecommitdiffstats
path: root/grub-core/kern/i386
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:29:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:29:51 +0000
commit6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e (patch)
tree32451fa3cdd9321fb2591fada9891b2cb70a9cd1 /grub-core/kern/i386
parentInitial commit. (diff)
downloadgrub2-upstream.tar.xz
grub2-upstream.zip
Adding upstream version 2.06.upstream/2.06upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'grub-core/kern/i386')
-rw-r--r--grub-core/kern/i386/coreboot/cbtable.c44
-rw-r--r--grub-core/kern/i386/coreboot/init.c143
-rw-r--r--grub-core/kern/i386/coreboot/startup.S62
-rw-r--r--grub-core/kern/i386/dl.c81
-rw-r--r--grub-core/kern/i386/efi/init.c48
-rw-r--r--grub-core/kern/i386/efi/startup.S36
-rw-r--r--grub-core/kern/i386/efi/tsc.c40
-rw-r--r--grub-core/kern/i386/ieee1275/startup.S40
-rw-r--r--grub-core/kern/i386/int.S134
-rw-r--r--grub-core/kern/i386/multiboot_mmap.c73
-rw-r--r--grub-core/kern/i386/pc/acpi.c83
-rw-r--r--grub-core/kern/i386/pc/init.c271
-rw-r--r--grub-core/kern/i386/pc/mmap.c193
-rw-r--r--grub-core/kern/i386/pc/startup.S217
-rw-r--r--grub-core/kern/i386/qemu/init.c276
-rw-r--r--grub-core/kern/i386/qemu/mmap.c107
-rw-r--r--grub-core/kern/i386/qemu/startup.S75
-rw-r--r--grub-core/kern/i386/realmode.S281
-rw-r--r--grub-core/kern/i386/tsc.c78
-rw-r--r--grub-core/kern/i386/tsc_pit.c84
-rw-r--r--grub-core/kern/i386/tsc_pmtimer.c88
-rw-r--r--grub-core/kern/i386/xen/hypercall.S43
-rw-r--r--grub-core/kern/i386/xen/pvh.c369
-rw-r--r--grub-core/kern/i386/xen/startup.S38
-rw-r--r--grub-core/kern/i386/xen/startup_pvh.S81
-rw-r--r--grub-core/kern/i386/xen/tsc.c40
26 files changed, 3025 insertions, 0 deletions
diff --git a/grub-core/kern/i386/coreboot/cbtable.c b/grub-core/kern/i386/coreboot/cbtable.c
new file mode 100644
index 0000000..34a2b59
--- /dev/null
+++ b/grub-core/kern/i386/coreboot/cbtable.c
@@ -0,0 +1,44 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2007,2008,2013 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/>.
+ */
+
+#include <grub/i386/coreboot/memory.h>
+#include <grub/coreboot/lbio.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+grub_linuxbios_table_header_t
+grub_linuxbios_get_tables (void)
+{
+ grub_linuxbios_table_header_t table_header;
+ /* Assuming table_header is aligned to its size (8 bytes). */
+ for (table_header = (grub_linuxbios_table_header_t) 0x500;
+ table_header < (grub_linuxbios_table_header_t) 0x1000; table_header++)
+ if (grub_linuxbios_check_signature (table_header))
+ return table_header;
+
+ for (table_header = (grub_linuxbios_table_header_t) 0xf0000;
+ table_header < (grub_linuxbios_table_header_t) 0x100000; table_header++)
+ if (grub_linuxbios_check_signature (table_header))
+ return table_header;
+
+ return 0;
+}
diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c
new file mode 100644
index 0000000..3314f02
--- /dev/null
+++ b/grub-core/kern/i386/coreboot/init.c
@@ -0,0 +1,143 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2013 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/>.
+ */
+
+#include <grub/kernel.h>
+#include <grub/mm.h>
+#include <grub/machine/time.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/console.h>
+#include <grub/offsets.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/loader.h>
+#include <grub/env.h>
+#include <grub/cache.h>
+#include <grub/time.h>
+#include <grub/symbol.h>
+#include <grub/cpu/io.h>
+#include <grub/cpu/floppy.h>
+#include <grub/cpu/tsc.h>
+#include <grub/video.h>
+
+extern grub_uint8_t _start[];
+extern grub_uint8_t _end[];
+extern grub_uint8_t _edata[];
+
+void __attribute__ ((noreturn))
+grub_exit (void)
+{
+ /* We can't use grub_fatal() in this function. This would create an infinite
+ loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit(). */
+ while (1)
+ grub_cpu_idle ();
+}
+
+grub_addr_t grub_modbase = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
+static grub_uint64_t modend;
+static int have_memory = 0;
+
+/* Helper for grub_machine_init. */
+static int
+heap_init (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
+ void *data __attribute__ ((unused)))
+{
+ grub_uint64_t begin = addr, end = addr + size;
+
+#if GRUB_CPU_SIZEOF_VOID_P == 4
+ /* Restrict ourselves to 32-bit memory space. */
+ if (begin > GRUB_ULONG_MAX)
+ return 0;
+ if (end > GRUB_ULONG_MAX)
+ end = GRUB_ULONG_MAX;
+#endif
+
+ if (type != GRUB_MEMORY_AVAILABLE)
+ return 0;
+
+ /* Avoid the lower memory. */
+ if (begin < GRUB_MEMORY_MACHINE_LOWER_SIZE)
+ begin = GRUB_MEMORY_MACHINE_LOWER_SIZE;
+
+ if (modend && begin < modend)
+ begin = modend;
+
+ if (end <= begin)
+ return 0;
+
+ grub_mm_init_region ((void *) (grub_addr_t) begin, (grub_size_t) (end - begin));
+
+ have_memory = 1;
+
+ return 0;
+}
+
+#ifndef GRUB_MACHINE_MULTIBOOT
+
+void
+grub_machine_init (void)
+{
+ modend = grub_modules_get_end ();
+
+ grub_video_coreboot_fb_early_init ();
+
+ grub_vga_text_init ();
+
+ grub_machine_mmap_iterate (heap_init, NULL);
+ if (!have_memory)
+ grub_fatal ("No memory found");
+
+ grub_video_coreboot_fb_late_init ();
+
+ grub_font_init ();
+ grub_gfxterm_init ();
+
+ grub_tsc_init ();
+}
+
+#else
+
+void
+grub_machine_init (void)
+{
+ modend = grub_modules_get_end ();
+
+ grub_vga_text_init ();
+
+ grub_machine_mmap_init ();
+ grub_machine_mmap_iterate (heap_init, NULL);
+
+ grub_tsc_init ();
+}
+
+#endif
+
+void
+grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
+ char **path __attribute__ ((unused)))
+{
+}
+
+void
+grub_machine_fini (int flags)
+{
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_vga_text_fini ();
+ grub_stop_floppy ();
+}
diff --git a/grub-core/kern/i386/coreboot/startup.S b/grub-core/kern/i386/coreboot/startup.S
new file mode 100644
index 0000000..df6adba
--- /dev/null
+++ b/grub-core/kern/i386/coreboot/startup.S
@@ -0,0 +1,62 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 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/>.
+ */
+
+#include <grub/symbol.h>
+#include <grub/machine/memory.h>
+#include <grub/offsets.h>
+#include <multiboot.h>
+#include <multiboot2.h>
+
+/*
+ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
+ * So the first three arguments are passed in %eax, %edx, and %ecx,
+ * respectively, and if a function has a fixed number of arguments
+ * and the number if greater than three, the function must return
+ * with "ret $N" where N is ((the number of arguments) - 3) * 4.
+ */
+
+ .file "startup.S"
+ .text
+ .globl start, _start
+start:
+_start:
+#ifdef GRUB_MACHINE_MULTIBOOT
+ cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
+ jne 0f
+ movl %ebx, EXT_C(startup_multiboot_info)
+0:
+#endif
+
+ /* initialize the stack */
+ movl $GRUB_MEMORY_MACHINE_PROT_STACK, %esp
+
+ /* jump to the main body of C code */
+ jmp EXT_C(grub_main)
+
+/*
+ * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
+ */
+ .p2align 2 /* force 4-byte alignment */
+multiboot_header:
+ /* magic */
+ .long 0x1BADB002
+ /* flags */
+ .long MULTIBOOT_MEMORY_INFO
+ /* checksum */
+ .long -0x1BADB002 - MULTIBOOT_MEMORY_INFO
+
diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c
new file mode 100644
index 0000000..1346da5
--- /dev/null
+++ b/grub-core/kern/i386/dl.c
@@ -0,0 +1,81 @@
+/* dl-386.c - arch-dependent part of loadable module support */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2005,2007,2009 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/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/elf.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/i18n.h>
+
+/* Check if EHDR is a valid ELF header. */
+grub_err_t
+grub_arch_dl_check_header (void *ehdr)
+{
+ Elf_Ehdr *e = ehdr;
+
+ /* Check the magic numbers. */
+ if (e->e_ident[EI_CLASS] != ELFCLASS32
+ || e->e_ident[EI_DATA] != ELFDATA2LSB
+ || e->e_machine != EM_386)
+ return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
+
+ return GRUB_ERR_NONE;
+}
+
+/* Relocate symbols. */
+grub_err_t
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ Elf_Shdr *s, grub_dl_segment_t seg)
+{
+ Elf_Rel *rel, *max;
+
+ for (rel = (Elf_Rel *) ((char *) ehdr + s->sh_offset),
+ max = (Elf_Rel *) ((char *) rel + s->sh_size);
+ rel < max;
+ rel = (Elf_Rel *) ((char *) rel + s->sh_entsize))
+ {
+ Elf_Word *addr;
+ Elf_Sym *sym;
+
+ if (seg->size < rel->r_offset)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "reloc offset is out of the segment");
+
+ addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset);
+ sym = (Elf_Sym *) ((char *) mod->symtab
+ + mod->symsize * ELF_R_SYM (rel->r_info));
+
+ switch (ELF_R_TYPE (rel->r_info))
+ {
+ case R_386_32:
+ *addr += sym->st_value;
+ break;
+
+ case R_386_PC32:
+ *addr += (sym->st_value - (grub_addr_t) addr);
+ break;
+ default:
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("relocation 0x%x is not implemented yet"),
+ ELF_R_TYPE (rel->r_info));
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/kern/i386/efi/init.c b/grub-core/kern/i386/efi/init.c
new file mode 100644
index 0000000..46476e2
--- /dev/null
+++ b/grub-core/kern/i386/efi/init.c
@@ -0,0 +1,48 @@
+/* init.c - initialize an x86-based EFI system */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,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/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/cache.h>
+#include <grub/kernel.h>
+#include <grub/efi/efi.h>
+#include <grub/i386/tsc.h>
+#include <grub/loader.h>
+
+void
+grub_machine_init (void)
+{
+ grub_efi_init ();
+ grub_tsc_init ();
+}
+
+void
+grub_machine_fini (int flags)
+{
+ if (!(flags & GRUB_LOADER_FLAG_NORETURN))
+ return;
+
+ grub_efi_fini ();
+
+ if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
+ grub_efi_memory_fini ();
+}
diff --git a/grub-core/kern/i386/efi/startup.S b/grub-core/kern/i386/efi/startup.S
new file mode 100644
index 0000000..fc5ea3d
--- /dev/null
+++ b/grub-core/kern/i386/efi/startup.S
@@ -0,0 +1,36 @@
+/* startup.S - bootstrap GRUB itself */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2010 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/>.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+
+ .file "startup.S"
+ .text
+ .globl start, _start
+start:
+_start:
+ /*
+ * EFI_SYSTEM_TABLE * and EFI_HANDLE are passed on the stack.
+ */
+ movl 4(%esp), %eax
+ movl %eax, EXT_C(grub_efi_image_handle)
+ movl 8(%esp), %eax
+ movl %eax, EXT_C(grub_efi_system_table)
+ call EXT_C(grub_main)
+ ret
diff --git a/grub-core/kern/i386/efi/tsc.c b/grub-core/kern/i386/efi/tsc.c
new file mode 100644
index 0000000..4b93ba8
--- /dev/null
+++ b/grub-core/kern/i386/efi/tsc.c
@@ -0,0 +1,40 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module uses the PIT to calibrate the TSC to
+ * real time.
+ *
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 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/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+
+int
+grub_tsc_calibrate_from_efi (void)
+{
+ grub_uint64_t start_tsc, end_tsc;
+ /* Use EFI Time Service to calibrate TSC */
+ start_tsc = grub_get_tsc ();
+ efi_call_1 (grub_efi_system_table->boot_services->stall, 1000);
+ end_tsc = grub_get_tsc ();
+ grub_tsc_rate = grub_divmod64 ((1ULL << 32), end_tsc - start_tsc, 0);
+ return 1;
+}
diff --git a/grub-core/kern/i386/ieee1275/startup.S b/grub-core/kern/i386/ieee1275/startup.S
new file mode 100644
index 0000000..62cf348
--- /dev/null
+++ b/grub-core/kern/i386/ieee1275/startup.S
@@ -0,0 +1,40 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 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/>.
+ */
+
+#include <grub/symbol.h>
+#include <grub/offsets.h>
+#include <multiboot.h>
+#include <multiboot2.h>
+
+/*
+ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
+ * So the first three arguments are passed in %eax, %edx, and %ecx,
+ * respectively, and if a function has a fixed number of arguments
+ * and the number if greater than three, the function must return
+ * with "ret $N" where N is ((the number of arguments) - 3) * 4.
+ */
+
+ .file "startup.S"
+ .text
+ .globl start, _start
+
+start:
+_start:
+ movl %eax, EXT_C(grub_ieee1275_entry_fn)
+ jmp EXT_C(grub_main)
+
diff --git a/grub-core/kern/i386/int.S b/grub-core/kern/i386/int.S
new file mode 100644
index 0000000..862a542
--- /dev/null
+++ b/grub-core/kern/i386/int.S
@@ -0,0 +1,134 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010,2011 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/>.
+ */
+
+FUNCTION(grub_bios_interrupt)
+ pushf
+ cli
+ popf
+ pushl %ebp
+ pushl %ecx
+ pushl %eax
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushl %edx
+
+ movb %al, intno
+ movl (%edx), %eax
+ movl %eax, LOCAL(bios_register_eax)
+ movw 4(%edx), %ax
+ movw %ax, LOCAL(bios_register_es)
+ movw 6(%edx), %ax
+ movw %ax, LOCAL(bios_register_ds)
+ movw 8(%edx), %ax
+ movw %ax, LOCAL(bios_register_flags)
+
+ movl 12(%edx), %ebx
+ movl 16(%edx), %ecx
+ movl 20(%edx), %edi
+ movl 24(%edx), %esi
+ movl 28(%edx), %edx
+
+ /*
+ Via C3 CPUs have cache coherence problems, so we need to call
+ wbinvd at these 2 points. As wbinvd slows down boot, don't do
+ it on non-VIA. 9090 is nop nop. */
+VARIABLE(grub_bios_via_workaround1)
+ .byte 0x90, 0x90
+
+ PROT_TO_REAL
+ .code16
+ pushf
+ cli
+
+ mov %ds, %ax
+ push %ax
+
+ /* movw imm16, %ax*/
+ .byte 0xb8
+LOCAL(bios_register_es):
+ .short 0
+ movw %ax, %es
+ /* movw imm16, %ax*/
+ .byte 0xb8
+LOCAL(bios_register_ds):
+ .short 0
+ movw %ax, %ds
+
+ /* movw imm16, %ax*/
+ .byte 0xb8
+LOCAL(bios_register_flags):
+ .short 0
+ push %ax
+ popf
+
+ /* movl imm32, %eax*/
+ .byte 0x66, 0xb8
+LOCAL(bios_register_eax):
+ .long 0
+
+ /* int imm8. */
+ .byte 0xcd
+intno:
+ .byte 0
+
+ movl %eax, %cs:LOCAL(bios_register_eax)
+ movw %ds, %ax
+ movw %ax, %cs:LOCAL(bios_register_ds)
+ pop %ax
+ mov %ax, %ds
+ pushf
+ pop %ax
+ movw %ax, LOCAL(bios_register_flags)
+ mov %es, %ax
+ movw %ax, LOCAL(bios_register_es)
+
+ popf
+
+VARIABLE(grub_bios_via_workaround2)
+ .byte 0x90, 0x90
+
+ REAL_TO_PROT
+ .code32
+
+ popl %eax
+
+ movl %ebx, 12(%eax)
+ movl %ecx, 16(%eax)
+ movl %edi, 20(%eax)
+ movl %esi, 24(%eax)
+ movl %edx, 28(%eax)
+
+ movl %eax, %edx
+
+ movl LOCAL(bios_register_eax), %eax
+ movl %eax, (%edx)
+ movw LOCAL(bios_register_es), %ax
+ movw %ax, 4(%edx)
+ movw LOCAL(bios_register_ds), %ax
+ movw %ax, 6(%edx)
+ movw LOCAL(bios_register_flags), %ax
+ movw %ax, 8(%edx)
+
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %eax
+ popl %ecx
+ popl %ebp
+ ret
diff --git a/grub-core/kern/i386/multiboot_mmap.c b/grub-core/kern/i386/multiboot_mmap.c
new file mode 100644
index 0000000..e8f4f34
--- /dev/null
+++ b/grub-core/kern/i386/multiboot_mmap.c
@@ -0,0 +1,73 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 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/>.
+ */
+
+#include <grub/machine/memory.h>
+#include <grub/types.h>
+#include <grub/multiboot.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+
+/* A pointer to the MBI in its initial location. */
+struct multiboot_info *startup_multiboot_info;
+
+/* The MBI has to be copied to our BSS so that it won't be
+ overwritten. This is its final location. */
+static struct multiboot_info kern_multiboot_info;
+
+/* Unfortunately we can't use heap at this point. But 32 looks like a sane
+ limit (used by memtest86). */
+static grub_uint8_t mmap_entries[sizeof (struct multiboot_mmap_entry) * 32];
+
+void
+grub_machine_mmap_init (void)
+{
+ if (! startup_multiboot_info)
+ grub_fatal ("Unable to find Multiboot Information (is CONFIG_MULTIBOOT disabled in coreboot?)");
+
+ /* Move MBI to a safe place. */
+ grub_memmove (&kern_multiboot_info, startup_multiboot_info, sizeof (struct multiboot_info));
+
+ if ((kern_multiboot_info.flags & MULTIBOOT_INFO_MEM_MAP) == 0)
+ grub_fatal ("Missing Multiboot memory information");
+
+ /* Move the memory map to a safe place. */
+ if (kern_multiboot_info.mmap_length > sizeof (mmap_entries))
+ {
+ grub_printf ("WARNING: Memory map size exceeds limit (0x%x > 0x%x); it will be truncated\n",
+ kern_multiboot_info.mmap_length, sizeof (mmap_entries));
+ kern_multiboot_info.mmap_length = sizeof (mmap_entries);
+ }
+ grub_memmove (mmap_entries, (void *) kern_multiboot_info.mmap_addr, kern_multiboot_info.mmap_length);
+ kern_multiboot_info.mmap_addr = (grub_uint32_t) mmap_entries;
+}
+
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
+{
+ struct multiboot_mmap_entry *entry = (void *) kern_multiboot_info.mmap_addr;
+
+ while ((unsigned long) entry < kern_multiboot_info.mmap_addr + kern_multiboot_info.mmap_length)
+ {
+ if (hook (entry->addr, entry->len, entry->type, hook_data))
+ break;
+
+ entry = (void *) ((grub_addr_t) entry + entry->size + sizeof (entry->size));
+ }
+
+ return 0;
+}
diff --git a/grub-core/kern/i386/pc/acpi.c b/grub-core/kern/i386/pc/acpi.c
new file mode 100644
index 0000000..297f5d0
--- /dev/null
+++ b/grub-core/kern/i386/pc/acpi.c
@@ -0,0 +1,83 @@
+/* acpi.c - get acpi tables. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/>.
+ */
+
+#include <grub/acpi.h>
+#include <grub/misc.h>
+
+struct grub_acpi_rsdp_v10 *
+grub_machine_acpi_get_rsdpv1 (void)
+{
+ int ebda_len;
+ grub_uint8_t *ebda, *ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
+ ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
+ ebda_len = * (grub_uint16_t *) ebda;
+ if (! ebda_len) /* FIXME do we really need this check? */
+ goto scan_bios;
+ for (ptr = ebda; ptr < ebda + 0x400; ptr += 16)
+ if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0)
+ return (struct grub_acpi_rsdp_v10 *) ptr;
+
+scan_bios:
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");
+ for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
+ ptr += 16)
+ if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0)
+ return (struct grub_acpi_rsdp_v10 *) ptr;
+ return 0;
+}
+
+struct grub_acpi_rsdp_v20 *
+grub_machine_acpi_get_rsdpv2 (void)
+{
+ int ebda_len;
+ grub_uint8_t *ebda, *ptr;
+
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");
+ ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4);
+ ebda_len = * (grub_uint16_t *) ebda;
+ if (! ebda_len) /* FIXME do we really need this check? */
+ goto scan_bios;
+ for (ptr = ebda; ptr < ebda + 0x400; ptr += 16)
+ if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0
+ && ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024
+ && grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length)
+ == 0)
+ return (struct grub_acpi_rsdp_v20 *) ptr;
+
+scan_bios:
+ grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");
+ for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
+ ptr += 16)
+ if (grub_memcmp (ptr, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
+ && grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0
+ && ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0
+ && ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024
+ && grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length)
+ == 0)
+ return (struct grub_acpi_rsdp_v20 *) ptr;
+ return 0;
+}
diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c
new file mode 100644
index 0000000..27bc68b
--- /dev/null
+++ b/grub-core/kern/i386/pc/init.c
@@ -0,0 +1,271 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 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/>.
+ */
+
+#include <grub/kernel.h>
+#include <grub/mm.h>
+#include <grub/machine/boot.h>
+#include <grub/i386/floppy.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/console.h>
+#include <grub/machine/kernel.h>
+#include <grub/machine/int.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/loader.h>
+#include <grub/env.h>
+#include <grub/cache.h>
+#include <grub/time.h>
+#include <grub/cpu/cpuid.h>
+#include <grub/cpu/tsc.h>
+#include <grub/machine/time.h>
+
+struct mem_region
+{
+ grub_addr_t addr;
+ grub_size_t size;
+};
+
+#define MAX_REGIONS 32
+
+static struct mem_region mem_regions[MAX_REGIONS];
+static int num_regions;
+
+void (*grub_pc_net_config) (char **device, char **path);
+
+/*
+ * return the real time in ticks, of which there are about
+ * 18-20 per second
+ */
+grub_uint64_t
+grub_rtc_get_time_ms (void)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.eax = 0;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x1a, &regs);
+
+ return ((regs.ecx << 16) | (regs.edx & 0xffff)) * 55ULL;
+}
+
+void
+grub_machine_get_bootlocation (char **device, char **path)
+{
+ char *ptr;
+ grub_uint8_t boot_drive, dos_part, bsd_part;
+
+ boot_drive = (grub_boot_device >> 24);
+ dos_part = (grub_boot_device >> 16);
+ bsd_part = (grub_boot_device >> 8);
+
+ /* No hardcoded root partition - make it from the boot drive and the
+ partition number encoded at the install time. */
+ if (boot_drive == GRUB_BOOT_MACHINE_PXE_DL)
+ {
+ if (grub_pc_net_config)
+ grub_pc_net_config (device, path);
+ return;
+ }
+
+ /* XXX: This should be enough. */
+#define DEV_SIZE 100
+ *device = grub_malloc (DEV_SIZE);
+ ptr = *device;
+ grub_snprintf (*device, DEV_SIZE,
+ "%cd%u", (boot_drive & 0x80) ? 'h' : 'f',
+ boot_drive & 0x7f);
+ ptr += grub_strlen (ptr);
+
+ if (dos_part != 0xff)
+ grub_snprintf (ptr, DEV_SIZE - (ptr - *device),
+ ",%u", dos_part + 1);
+ ptr += grub_strlen (ptr);
+
+ if (bsd_part != 0xff)
+ grub_snprintf (ptr, DEV_SIZE - (ptr - *device), ",%u",
+ bsd_part + 1);
+ ptr += grub_strlen (ptr);
+ *ptr = 0;
+}
+
+/* Add a memory region. */
+static void
+add_mem_region (grub_addr_t addr, grub_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);
+
+ grub_memmove (mem_regions + j, mem_regions + j + 1,
+ (num_regions - j - 1) * sizeof (struct mem_region));
+ i--;
+ num_regions--;
+ }
+}
+
+grub_addr_t grub_modbase;
+extern grub_uint8_t _start[], _edata[];
+
+/* Helper for grub_machine_init. */
+static int
+mmap_iterate_hook (grub_uint64_t addr, grub_uint64_t size,
+ grub_memory_type_t type,
+ void *data __attribute__ ((unused)))
+{
+ /* Avoid the lower memory. */
+ if (addr < GRUB_MEMORY_MACHINE_UPPER_START)
+ {
+ if (size <= GRUB_MEMORY_MACHINE_UPPER_START - addr)
+ return 0;
+
+ size -= GRUB_MEMORY_MACHINE_UPPER_START - addr;
+ addr = GRUB_MEMORY_MACHINE_UPPER_START;
+ }
+
+ /* Ignore >4GB. */
+ if (addr <= 0xFFFFFFFF && type == GRUB_MEMORY_AVAILABLE)
+ {
+ grub_size_t len;
+
+ len = (grub_size_t) ((addr + size > 0xFFFFFFFF)
+ ? 0xFFFFFFFF - addr
+ : size);
+ add_mem_region (addr, len);
+ }
+
+ return 0;
+}
+
+extern grub_uint16_t grub_bios_via_workaround1, grub_bios_via_workaround2;
+
+/* Via needs additional wbinvd. */
+static void
+grub_via_workaround_init (void)
+{
+ grub_uint32_t manufacturer[3], max_cpuid;
+ if (! grub_cpu_is_cpuid_supported ())
+ return;
+
+ grub_cpuid (0, max_cpuid, manufacturer[0], manufacturer[2], manufacturer[1]);
+
+ if (grub_memcmp (manufacturer, "CentaurHauls", 12) != 0)
+ return;
+
+ grub_bios_via_workaround1 = 0x090f;
+ grub_bios_via_workaround2 = 0x090f;
+ asm volatile ("wbinvd");
+}
+
+void
+grub_machine_init (void)
+{
+ int i;
+#if 0
+ int grub_lower_mem;
+#endif
+ grub_addr_t modend;
+
+ /* This has to happen before any BIOS calls. */
+ grub_via_workaround_init ();
+
+ grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start);
+
+ /* Initialize the console as early as possible. */
+ grub_console_init ();
+
+ /* This sanity check is useless since top of GRUB_MEMORY_MACHINE_RESERVED_END
+ is used for stack and if it's unavailable we wouldn't have gotten so far.
+ */
+#if 0
+ grub_lower_mem = grub_get_conv_memsize () << 10;
+
+ /* Sanity check. */
+ if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END)
+ grub_fatal ("too small memory");
+#endif
+
+/* FIXME: This prevents loader/i386/linux.c from using low memory. When our
+ heap implements support for requesting a chunk in low memory, this should
+ no longer be a problem. */
+#if 0
+ /* Add the lower memory into free memory. */
+ if (grub_lower_mem >= GRUB_MEMORY_MACHINE_RESERVED_END)
+ add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END,
+ grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);
+#endif
+
+ grub_machine_mmap_iterate (mmap_iterate_hook, NULL);
+
+ compact_mem_regions ();
+
+ modend = grub_modules_get_end ();
+ for (i = 0; i < num_regions; i++)
+ {
+ grub_addr_t beg = mem_regions[i].addr;
+ grub_addr_t fin = mem_regions[i].addr + mem_regions[i].size;
+ if (modend && beg < modend)
+ beg = modend;
+ if (beg >= fin)
+ continue;
+ grub_mm_init_region ((void *) beg, fin - beg);
+ }
+
+ grub_tsc_init ();
+}
+
+void
+grub_machine_fini (int flags)
+{
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_console_fini ();
+ grub_stop_floppy ();
+}
diff --git a/grub-core/kern/i386/pc/mmap.c b/grub-core/kern/i386/pc/mmap.c
new file mode 100644
index 0000000..c0c3c35
--- /dev/null
+++ b/grub-core/kern/i386/pc/mmap.c
@@ -0,0 +1,193 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008 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/>.
+ */
+
+#include <grub/machine/memory.h>
+#include <grub/machine/int.h>
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+
+struct grub_machine_mmap_entry
+{
+ grub_uint32_t size;
+ grub_uint64_t addr;
+ grub_uint64_t len;
+#define GRUB_MACHINE_MEMORY_AVAILABLE 1
+#define GRUB_MACHINE_MEMORY_RESERVED 2
+#define GRUB_MACHINE_MEMORY_ACPI 3
+#define GRUB_MACHINE_MEMORY_NVS 4
+#define GRUB_MACHINE_MEMORY_BADRAM 5
+ grub_uint32_t type;
+} GRUB_PACKED;
+
+
+/*
+ *
+ * grub_get_conv_memsize(i) : return the conventional memory size in KB.
+ * BIOS call "INT 12H" to get conventional memory size
+ * The return value in AX.
+ */
+static inline grub_uint16_t
+grub_get_conv_memsize (void)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x12, &regs);
+ return regs.eax & 0xffff;
+}
+
+/*
+ * grub_get_ext_memsize() : return the extended memory size in KB.
+ * BIOS call "INT 15H, AH=88H" to get extended memory size
+ * The return value in AX.
+ *
+ */
+static inline grub_uint16_t
+grub_get_ext_memsize (void)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.eax = 0x8800;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+ return regs.eax & 0xffff;
+}
+
+/* Get a packed EISA memory map. Lower 16 bits are between 1MB and 16MB
+ in 1KB parts, and upper 16 bits are above 16MB in 64KB parts. If error, return zero.
+ BIOS call "INT 15H, AH=E801H" to get EISA memory map,
+ AX = memory between 1M and 16M in 1K parts.
+ BX = memory above 16M in 64K parts.
+*/
+
+static inline grub_uint32_t
+grub_get_eisa_mmap (void)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ regs.eax = 0xe801;
+ grub_bios_interrupt (0x15, &regs);
+
+ if ((regs.eax & 0xff00) == 0x8600)
+ return 0;
+
+ return (regs.eax & 0xffff) | (regs.ebx << 16);
+}
+
+/*
+ *
+ * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
+ * start), for the Query System Address Map BIOS call.
+ *
+ * Sets the first 4-byte int value of "addr" to the size returned by
+ * the call. If the call fails, sets it to zero.
+ *
+ * Returns: new (non-zero) continuation value, 0 if done.
+ */
+/* Get a memory map entry. Return next continuation value. Zero means
+ the end. */
+static grub_uint32_t
+grub_get_mmap_entry (struct grub_machine_mmap_entry *entry,
+ grub_uint32_t cont)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+
+ /* place address (+4) in ES:DI */
+ regs.es = ((grub_addr_t) &entry->addr) >> 4;
+ regs.edi = ((grub_addr_t) &entry->addr) & 0xf;
+
+ /* set continuation value */
+ regs.ebx = cont;
+
+ /* set default maximum buffer size */
+ regs.ecx = sizeof (*entry) - sizeof (entry->size);
+
+ /* set EDX to 'SMAP' */
+ regs.edx = 0x534d4150;
+
+ regs.eax = 0xe820;
+ grub_bios_interrupt (0x15, &regs);
+
+ /* write length of buffer (zero if error) into ADDR */
+ if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) || regs.eax != 0x534d4150
+ || regs.ecx < 0x14 || regs.ecx > 0x400)
+ entry->size = 0;
+ else
+ entry->size = regs.ecx;
+
+ /* return the continuation value */
+ return regs.ebx;
+}
+
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
+{
+ grub_uint32_t cont = 0;
+ struct grub_machine_mmap_entry *entry
+ = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+ int e820_works = 0;
+
+ while (1)
+ {
+ grub_memset (entry, 0, sizeof (*entry));
+
+ cont = grub_get_mmap_entry (entry, cont);
+
+ if (!entry->size)
+ break;
+
+ if (entry->len)
+ e820_works = 1;
+ if (entry->len
+ && hook (entry->addr, entry->len,
+ /* GRUB mmaps have been defined to match with
+ the E820 definition.
+ Therefore, we can just pass type through. */
+ entry->type, hook_data))
+ break;
+
+ if (! cont)
+ break;
+ }
+
+ if (!e820_works)
+ {
+ grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
+
+ if (hook (0x0, ((grub_uint32_t) grub_get_conv_memsize ()) << 10,
+ GRUB_MEMORY_AVAILABLE, hook_data))
+ return 0;
+
+ if (eisa_mmap)
+ {
+ if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10,
+ GRUB_MEMORY_AVAILABLE, hook_data) == 0)
+ hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MEMORY_AVAILABLE,
+ hook_data);
+ }
+ else
+ hook (0x100000, ((grub_uint32_t) grub_get_ext_memsize ()) << 10,
+ GRUB_MEMORY_AVAILABLE, hook_data);
+ }
+
+ return 0;
+}
diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S
new file mode 100644
index 0000000..b8a9b33
--- /dev/null
+++ b/grub-core/kern/i386/pc/startup.S
@@ -0,0 +1,217 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009,2011 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/>.
+ */
+
+
+/*
+ * Note: These functions defined in this file may be called from C.
+ * Be careful of that you must not modify some registers. Quote
+ * from gcc-2.95.2/gcc/config/i386/i386.h:
+
+ 1 for registers not available across function calls.
+ These must include the FIXED_REGISTERS and also any
+ registers that can be used without being saved.
+ The latter must include the registers where values are returned
+ and the register where structure-value addresses are passed.
+ Aside from that, you can include as many other registers as you like.
+
+ ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
+{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
+ */
+
+/*
+ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
+ * So the first three arguments are passed in %eax, %edx, and %ecx,
+ * respectively, and if a function has a fixed number of arguments
+ * and the number is greater than three, the function must return
+ * with "ret $N" where N is ((the number of arguments) - 3) * 4.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+#include <multiboot.h>
+#ifdef __APPLE__
+#include <grub/i386/pc/memory.h>
+#endif
+
+ .file "startup.S"
+
+ .text
+
+ .globl start, _start, __start
+start:
+_start:
+__start:
+#ifdef __APPLE__
+LOCAL(start):
+#endif
+ .code32
+
+ movl %ecx, (LOCAL(real_to_prot_addr) - _start) (%esi)
+ movl %edi, (LOCAL(prot_to_real_addr) - _start) (%esi)
+ movl %eax, (EXT_C(grub_realidt) - _start) (%esi)
+
+ /* copy back the decompressed part (except the modules) */
+#ifdef __APPLE__
+ movl $EXT_C(_edata), %ecx
+ subl $LOCAL(start), %ecx
+#else
+ movl $(_edata - _start), %ecx
+#endif
+ movl $(_start), %edi
+ rep
+ movsb
+
+ movl $LOCAL (cont), %esi
+ jmp *%esi
+LOCAL(cont):
+
+#if 0
+ /* copy modules before cleaning out the bss */
+ movl EXT_C(grub_total_module_size), %ecx
+ movl EXT_C(grub_kernel_image_size), %esi
+ addl %ecx, %esi
+ addl $_start, %esi
+ decl %esi
+ movl $END_SYMBOL, %edi
+ addl %ecx, %edi
+ decl %edi
+ std
+ rep
+ movsb
+#endif
+
+#ifdef __APPLE__
+ /* clean out the bss */
+ movl $EXT_C(_edata), %edi
+
+ /* compute the bss length */
+ movl $GRUB_MEMORY_MACHINE_SCRATCH_ADDR, %ecx
+#else
+ /* clean out the bss */
+ movl $BSS_START_SYMBOL, %edi
+
+ /* compute the bss length */
+ movl $END_SYMBOL, %ecx
+#endif
+ subl %edi, %ecx
+
+ /* clean out */
+ xorl %eax, %eax
+ cld
+ rep
+ stosb
+
+ movl %edx, EXT_C(grub_boot_device)
+
+ /*
+ * Call the start of main body of C code.
+ */
+ call EXT_C(grub_main)
+
+LOCAL(real_to_prot_addr):
+ .long 0
+LOCAL(prot_to_real_addr):
+ .long 0
+
+ .macro PROT_TO_REAL
+ movl LOCAL(prot_to_real_addr), %eax
+ call *%eax
+ .endm
+
+ .macro REAL_TO_PROT
+ movl LOCAL(real_to_prot_addr), %eax
+ calll *%eax
+ .endm
+
+/*
+ * grub_exit()
+ *
+ * Exit the system.
+ */
+FUNCTION(grub_exit)
+ PROT_TO_REAL
+ .code16
+ /* Tell the BIOS a boot failure. If this does not work, reboot. */
+ int $0x18
+ /* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */
+ xorw %ax, %ax
+ movw $0x0472, %di
+ movw %ax, (%di)
+ ljmp $0xf000, $0xfff0
+ .code32
+
+/*
+ * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry);
+ */
+FUNCTION(grub_pxe_call)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl %ecx, %ebx
+ movl %eax, %ecx
+ movl %edx, %eax
+ andl $0xF, %eax
+ shrl $4, %edx
+ shll $16, %edx
+ addl %eax, %edx
+
+ PROT_TO_REAL
+ .code16
+
+ pushl %ebx
+ pushl %edx
+ pushw %cx
+ movw %sp, %bx
+ lcall *%ss:6(%bx)
+ cld
+ addw $10, %sp
+ movw %ax, %cx
+
+ REAL_TO_PROT
+ .code32
+
+ movzwl %cx, %eax
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ ret
+
+#include "../int.S"
+
+VARIABLE(grub_realidt)
+ .long 0
+
+#ifdef __APPLE__
+ /* Older versions of objconv assume that there is the same number
+ of text and data sections. Hence this dummy. */
+ .section __TEXT, __zz_dummy
+ .byte 0
+ .globl EXT_C(_edata)
+ .globl EXT_C(grub_boot_device)
+ .zerofill __DATA, __aa_before_bss, EXT_C(_edata), 1, 0
+ .zerofill __DATA, __bss, EXT_C(grub_boot_device), 4, 2
+#else
+ .bss
+VARIABLE(grub_boot_device)
+ .long 0
+#endif
diff --git a/grub-core/kern/i386/qemu/init.c b/grub-core/kern/i386/qemu/init.c
new file mode 100644
index 0000000..271b6fb
--- /dev/null
+++ b/grub-core/kern/i386/qemu/init.c
@@ -0,0 +1,276 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2013 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/>.
+ */
+
+#include <grub/kernel.h>
+#include <grub/mm.h>
+#include <grub/machine/time.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/console.h>
+#include <grub/offsets.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/loader.h>
+#include <grub/env.h>
+#include <grub/cache.h>
+#include <grub/time.h>
+#include <grub/symbol.h>
+#include <grub/cpu/io.h>
+#include <grub/cpu/floppy.h>
+#include <grub/cpu/tsc.h>
+#include <grub/machine/kernel.h>
+#include <grub/pci.h>
+
+extern grub_uint8_t _start[];
+extern grub_uint8_t _end[];
+extern grub_uint8_t _edata[];
+
+void __attribute__ ((noreturn))
+grub_exit (void)
+{
+ /* We can't use grub_fatal() in this function. This would create an infinite
+ loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit(). */
+ while (1)
+ grub_cpu_idle ();
+}
+
+grub_addr_t grub_modbase;
+
+/* Helper for grub_machine_init. */
+static int
+heap_init (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
+ void *data __attribute__ ((unused)))
+{
+ grub_uint64_t begin = addr, end = addr + size;
+
+#if GRUB_CPU_SIZEOF_VOID_P == 4
+ /* Restrict ourselves to 32-bit memory space. */
+ if (begin > GRUB_ULONG_MAX)
+ return 0;
+ if (end > GRUB_ULONG_MAX)
+ end = GRUB_ULONG_MAX;
+#endif
+
+ if (type != GRUB_MEMORY_AVAILABLE)
+ return 0;
+
+ /* Avoid the lower memory. */
+ if (begin < GRUB_MEMORY_MACHINE_LOWER_SIZE)
+ begin = GRUB_MEMORY_MACHINE_LOWER_SIZE;
+
+ if (end <= begin)
+ return 0;
+
+ grub_mm_init_region ((void *) (grub_addr_t) begin, (grub_size_t) (end - begin));
+
+ return 0;
+}
+
+struct resource
+{
+ grub_pci_device_t dev;
+ grub_size_t size;
+ unsigned type:4;
+ unsigned bar:3;
+};
+
+struct iterator_ctx
+{
+ struct resource *resources;
+ grub_size_t nresources;
+};
+
+/* We don't support bridges, so can't have more than 32 devices. */
+#define MAX_DEVICES 32
+
+static int
+find_resources (grub_pci_device_t dev,
+ grub_pci_id_t pciid __attribute__ ((unused)),
+ void *data)
+{
+ struct iterator_ctx *ctx = data;
+ int bar;
+
+ if (ctx->nresources >= MAX_DEVICES * 6)
+ return 1;
+
+ for (bar = 0; bar < 6; bar++)
+ {
+ grub_pci_address_t addr;
+ grub_uint32_t ones, zeros, mask;
+ struct resource *res;
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0
+ + 4 * bar);
+ grub_pci_write (addr, 0xffffffff);
+ grub_pci_read (addr);
+ ones = grub_pci_read (addr);
+ grub_pci_write (addr, 0);
+ grub_pci_read (addr);
+ zeros = grub_pci_read (addr);
+ if (ones == zeros)
+ continue;
+ res = &ctx->resources[ctx->nresources++];
+ if ((zeros & GRUB_PCI_ADDR_SPACE_MASK) == GRUB_PCI_ADDR_SPACE_IO)
+ mask = GRUB_PCI_ADDR_SPACE_MASK;
+ else
+ mask = (GRUB_PCI_ADDR_MEM_TYPE_MASK | GRUB_PCI_ADDR_SPACE_MASK | GRUB_PCI_ADDR_MEM_PREFETCH);
+
+ res->type = ones & mask;
+ res->dev = dev;
+ res->bar = bar;
+ res->size = (~((zeros ^ ones)) | mask) + 1;
+ if ((zeros & (GRUB_PCI_ADDR_MEM_TYPE_MASK | GRUB_PCI_ADDR_SPACE_MASK))
+ == (GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_64))
+ bar++;
+ }
+ return 0;
+}
+
+static int
+enable_cards (grub_pci_device_t dev,
+ grub_pci_id_t pciid __attribute__ ((unused)),
+ void *data __attribute__ ((unused)))
+{
+ grub_uint16_t cmd = 0;
+ grub_pci_address_t addr;
+ grub_uint32_t class;
+ int bar;
+
+ for (bar = 0; bar < 6; bar++)
+ {
+ grub_uint32_t val;
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0
+ + 4 * bar);
+ val = grub_pci_read (addr);
+ if (!val)
+ continue;
+ if ((val & GRUB_PCI_ADDR_SPACE_MASK) == GRUB_PCI_ADDR_SPACE_IO)
+ cmd |= GRUB_PCI_COMMAND_IO_ENABLED;
+ else
+ cmd |= GRUB_PCI_COMMAND_MEM_ENABLED;
+ }
+
+ class = (grub_pci_read (addr) >> 16) & 0xffff;
+
+ if (class == GRUB_PCI_CLASS_SUBCLASS_VGA)
+ cmd |= GRUB_PCI_COMMAND_IO_ENABLED
+ | GRUB_PCI_COMMAND_MEM_ENABLED;
+
+ if (class == GRUB_PCI_CLASS_SUBCLASS_USB)
+ return 0;
+
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
+ grub_pci_write (addr, cmd);
+
+ return 0;
+}
+
+static void
+grub_pci_assign_addresses (void)
+{
+ struct iterator_ctx ctx;
+
+ {
+ struct resource resources[MAX_DEVICES * 6];
+ int done;
+ unsigned i;
+ ctx.nresources = 0;
+ ctx.resources = resources;
+ grub_uint32_t memptr = 0xf0000000;
+ grub_uint16_t ioptr = 0x1000;
+
+ grub_pci_iterate (find_resources, &ctx);
+ /* FIXME: do we need a better sort here? */
+ do
+ {
+ done = 0;
+ for (i = 0; i + 1 < ctx.nresources; i++)
+ if (resources[i].size < resources[i+1].size)
+ {
+ struct resource t;
+ t = resources[i];
+ resources[i] = resources[i+1];
+ resources[i+1] = t;
+ done = 1;
+ }
+ }
+ while (done);
+
+ for (i = 0; i < ctx.nresources; i++)
+ {
+ grub_pci_address_t addr;
+ addr = grub_pci_make_address (resources[i].dev,
+ GRUB_PCI_REG_ADDRESS_REG0
+ + 4 * resources[i].bar);
+ if ((resources[i].type & GRUB_PCI_ADDR_SPACE_MASK)
+ == GRUB_PCI_ADDR_SPACE_IO)
+ {
+ grub_pci_write (addr, ioptr | resources[i].type);
+ ioptr += resources[i].size;
+ }
+ else
+ {
+ grub_pci_write (addr, memptr | resources[i].type);
+ memptr += resources[i].size;
+ if ((resources[i].type & (GRUB_PCI_ADDR_MEM_TYPE_MASK
+ | GRUB_PCI_ADDR_SPACE_MASK))
+ == (GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_64))
+ {
+ addr = grub_pci_make_address (resources[i].dev,
+ GRUB_PCI_REG_ADDRESS_REG0
+ + 4 * resources[i].bar + 4);
+ grub_pci_write (addr, 0);
+ }
+ }
+ }
+ grub_pci_iterate (enable_cards, NULL);
+ }
+}
+
+void
+grub_machine_init (void)
+{
+ grub_modbase = grub_core_entry_addr + (_edata - _start);
+
+ grub_pci_assign_addresses ();
+
+ grub_qemu_init_cirrus ();
+
+ grub_vga_text_init ();
+
+ grub_machine_mmap_init ();
+ grub_machine_mmap_iterate (heap_init, NULL);
+
+
+ grub_tsc_init ();
+}
+
+void
+grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
+ char **path __attribute__ ((unused)))
+{
+}
+
+void
+grub_machine_fini (int flags)
+{
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_vga_text_fini ();
+ grub_stop_floppy ();
+}
diff --git a/grub-core/kern/i386/qemu/mmap.c b/grub-core/kern/i386/qemu/mmap.c
new file mode 100644
index 0000000..f449637
--- /dev/null
+++ b/grub-core/kern/i386/qemu/mmap.c
@@ -0,0 +1,107 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/>.
+ */
+
+#include <grub/i386/memory.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/boot.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/cmos.h>
+#include <grub/offsets.h>
+
+#define QEMU_CMOS_MEMSIZE_HIGH 0x35
+#define QEMU_CMOS_MEMSIZE_LOW 0x34
+
+#define QEMU_CMOS_MEMSIZE2_HIGH 0x31
+#define QEMU_CMOS_MEMSIZE2_LOW 0x30
+
+#define min(a,b) ((a) > (b) ? (b) : (a))
+
+extern char _start[];
+extern char _end[];
+
+static grub_uint64_t mem_size, above_4g;
+
+void
+grub_machine_mmap_init (void)
+{
+ grub_uint8_t high, low, b, c, d;
+ grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH, &high);
+ grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW, &low);
+ mem_size = ((grub_uint64_t) high) << 24
+ | ((grub_uint64_t) low) << 16;
+ if (mem_size > 0)
+ {
+ /* Don't ask... */
+ mem_size += (16 * 1024 * 1024);
+ }
+ else
+ {
+ grub_cmos_read (QEMU_CMOS_MEMSIZE2_HIGH, &high);
+ grub_cmos_read (QEMU_CMOS_MEMSIZE2_LOW, &low);
+ mem_size
+ = ((((grub_uint64_t) high) << 18) | (((grub_uint64_t) low) << 10))
+ + 1024 * 1024;
+ }
+
+ grub_cmos_read (0x5b, &b);
+ grub_cmos_read (0x5c, &c);
+ grub_cmos_read (0x5d, &d);
+ above_4g = (((grub_uint64_t) b) << 16)
+ | (((grub_uint64_t) c) << 24)
+ | (((grub_uint64_t) d) << 32);
+}
+
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
+{
+ if (hook (0x0,
+ (grub_addr_t) _start,
+ GRUB_MEMORY_AVAILABLE, hook_data))
+ return 1;
+
+ if (hook ((grub_addr_t) _end,
+ 0xa0000 - (grub_addr_t) _end,
+ GRUB_MEMORY_AVAILABLE, hook_data))
+ return 1;
+
+ if (hook (GRUB_MEMORY_MACHINE_UPPER,
+ 0x100000 - GRUB_MEMORY_MACHINE_UPPER,
+ GRUB_MEMORY_RESERVED, hook_data))
+ return 1;
+
+ /* Everything else is free. */
+ if (hook (0x100000,
+ min (mem_size, (grub_uint32_t) -GRUB_BOOT_MACHINE_SIZE) - 0x100000,
+ GRUB_MEMORY_AVAILABLE, hook_data))
+ return 1;
+
+ /* Protect boot.img, which contains the gdt. It is mapped at the top of memory
+ (it is also mapped below 0x100000, but we already reserved that area). */
+ if (hook ((grub_uint32_t) -GRUB_BOOT_MACHINE_SIZE,
+ GRUB_BOOT_MACHINE_SIZE,
+ GRUB_MEMORY_RESERVED, hook_data))
+ return 1;
+
+ if (above_4g != 0 && hook (0x100000000ULL, above_4g,
+ GRUB_MEMORY_AVAILABLE, hook_data))
+ return 1;
+
+ return 0;
+}
diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S
new file mode 100644
index 0000000..0d89858
--- /dev/null
+++ b/grub-core/kern/i386/qemu/startup.S
@@ -0,0 +1,75 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 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/>.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+
+#include <grub/machine/memory.h>
+#include <grub/machine/kernel.h>
+
+ .text
+ .code32
+ .globl _start
+_start:
+ jmp codestart
+
+ .org GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR
+VARIABLE(grub_core_entry_addr)
+ .long 0
+
+codestart:
+ /* Relocate to low memory. First we figure out our location.
+ We will derive the rom start address from it. */
+ call 1f
+1: popl %esi
+
+ /* Rom size is a multiple of 64 kiB. With this we get the
+ value of `grub_core_entry_addr' in %esi. */
+ xorw %si, %si
+
+ movl $(_edata - _start), %ecx
+ movl $_start, %edi
+ cld
+ rep
+ movsb
+ ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $1f
+1:
+
+ /* clean out the bss */
+ movl $BSS_START_SYMBOL, %edi
+
+ /* compute the bss length */
+ movl $END_SYMBOL, %ecx
+ subl %edi, %ecx
+
+ /* clean out */
+ xorl %eax, %eax
+ cld
+ rep
+ stosb
+
+ /*
+ * Call the start of main body of C code.
+ */
+ call EXT_C(grub_main)
+
+ /* This should never happen. */
+ cli
+1:
+ hlt
+ jmp 1b
diff --git a/grub-core/kern/i386/realmode.S b/grub-core/kern/i386/realmode.S
new file mode 100644
index 0000000..265cdcb
--- /dev/null
+++ b/grub-core/kern/i386/realmode.S
@@ -0,0 +1,281 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009,2010 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/>.
+ */
+
+#include <grub/machine/memory.h>
+
+/*
+ * Note: These functions defined in this file may be called from C.
+ * Be careful of that you must not modify some registers. Quote
+ * from gcc-2.95.2/gcc/config/i386/i386.h:
+
+ 1 for registers not available across function calls.
+ These must include the FIXED_REGISTERS and also any
+ registers that can be used without being saved.
+ The latter must include the registers where values are returned
+ and the register where structure-value addresses are passed.
+ Aside from that, you can include as many other registers as you like.
+
+ ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
+{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
+ */
+
+/*
+ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
+ * So the first three arguments are passed in %eax, %edx, and %ecx,
+ * respectively, and if a function has a fixed number of arguments
+ * and the number if greater than three, the function must return
+ * with "ret $N" where N is ((the number of arguments) - 3) * 4.
+ */
+
+/*
+ * This is the area for all of the special variables.
+ */
+
+protstack:
+ .long GRUB_MEMORY_MACHINE_PROT_STACK
+
+ .macro PROT_TO_REAL
+ call prot_to_real
+ .endm
+
+ .macro REAL_TO_PROT
+ calll real_to_prot
+ .endm
+
+/*
+ * This is the Global Descriptor Table
+ *
+ * An entry, a "Segment Descriptor", looks like this:
+ *
+ * 31 24 19 16 7 0
+ * ------------------------------------------------------------
+ * | | |B| |A| | | |1|0|E|W|A| |
+ * | BASE 31..24 |G|/|L|V| LIMIT |P|DPL| TYPE | BASE 23:16 | 4
+ * | | |D| |L| 19..16| | |1|1|C|R|A| |
+ * ------------------------------------------------------------
+ * | | |
+ * | BASE 15..0 | LIMIT 15..0 | 0
+ * | | |
+ * ------------------------------------------------------------
+ *
+ * Note the ordering of the data items is reversed from the above
+ * description.
+ */
+
+ .p2align 5 /* force 32-byte alignment */
+gdt:
+ .word 0, 0
+ .byte 0, 0, 0, 0
+
+ /* -- code segment --
+ * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present
+ * type = 32bit code execute/read, DPL = 0
+ */
+ .word 0xFFFF, 0
+ .byte 0, 0x9A, 0xCF, 0
+
+ /* -- data segment --
+ * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
+ * type = 32 bit data read/write, DPL = 0
+ */
+ .word 0xFFFF, 0
+ .byte 0, 0x92, 0xCF, 0
+
+ /* -- 16 bit real mode CS --
+ * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
+ * type = 16 bit code execute/read only/conforming, DPL = 0
+ */
+ .word 0xFFFF, 0
+ .byte 0, 0x9E, 0, 0
+
+ /* -- 16 bit real mode DS --
+ * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
+ * type = 16 bit data read/write, DPL = 0
+ */
+ .word 0xFFFF, 0
+ .byte 0, 0x92, 0, 0
+
+
+ .p2align 5
+/* this is the GDT descriptor */
+gdtdesc:
+ .word 0x27 /* limit */
+ .long gdt /* addr */
+LOCAL(realidt):
+ .word 0x400
+ .long 0
+protidt:
+ .word 0
+ .long 0
+
+/*
+ * These next two routines, "real_to_prot" and "prot_to_real" are structured
+ * in a very specific way. Be very careful when changing them.
+ *
+ * NOTE: Use of either one messes up %eax and %ebp.
+ */
+
+real_to_prot:
+ .code16
+ cli
+
+ /* load the GDT register */
+ xorw %ax, %ax
+ movw %ax, %ds
+#ifdef GRUB_MACHINE_QEMU
+ /*
+ qemu is special: gdtdesc is in ROM.
+ %cs = 0xf000
+ _start + GRUB_BOOT_MACHINE_SIZE = 0x100000
+ So
+ _start + GRUB_BOOT_MACHINE_SIZE - 0x10000 points to the same point
+ as %cs.
+ gdtdesc - (_start + GRUB_BOOT_MACHINE_SIZE - 0x10000)
+ = gdtdesc - _start - GRUB_BOOT_MACHINE_SIZE + 0x10000
+ but the later can be computed by assembly.
+ */
+ lgdtl %cs:(gdtdesc - _start - GRUB_BOOT_MACHINE_SIZE + 0x10000)
+#else
+ lgdtl gdtdesc
+#endif
+
+ /* turn on protected mode */
+ movl %cr0, %eax
+ orl $GRUB_MEMORY_CPU_CR0_PE_ON, %eax
+ movl %eax, %cr0
+
+ /* jump to relocation, flush prefetch queue, and reload %cs */
+ ljmpl $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
+
+ .code32
+protcseg:
+ /* reload other segment registers */
+ movw $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
+ /* put the return address in a known safe location */
+ movl (%esp), %eax
+ movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
+
+ /* get protected mode stack */
+ movl protstack, %eax
+ movl %eax, %esp
+ movl %eax, %ebp
+
+ /* get return address onto the right stack */
+ movl GRUB_MEMORY_MACHINE_REAL_STACK, %eax
+ movl %eax, (%esp)
+
+ /* zero %eax */
+ xorl %eax, %eax
+
+ sidt LOCAL(realidt)
+ lidt protidt
+
+ /* return on the old (or initialized) stack! */
+ ret
+ /* prot_to_real assumes that this code is under 64K which is not
+ true for qemu. */
+#ifndef GRUB_MACHINE_QEMU
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009,2010 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/>.
+ */
+
+prot_to_real:
+ /* just in case, set GDT */
+ lgdt gdtdesc
+
+ sidt protidt
+ lidt LOCAL(realidt)
+
+ /* save the protected mode stack */
+ movl %esp, %eax
+ movl %eax, protstack
+
+ /* get the return address */
+ movl (%esp), %eax
+ movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
+
+ /* set up new stack */
+ movl $GRUB_MEMORY_MACHINE_REAL_STACK, %eax
+ movl %eax, %esp
+ movl %eax, %ebp
+
+ /* set up segment limits */
+ movw $GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
+ /* this might be an extra step */
+ /* jump to a 16 bit segment */
+ ljmp $GRUB_MEMORY_MACHINE_PSEUDO_REAL_CSEG, $tmpcseg
+
+tmpcseg:
+ .code16
+
+ /* clear the PE bit of CR0 */
+ movl %cr0, %eax
+ andl $(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax
+ movl %eax, %cr0
+
+ /* flush prefetch queue, reload %cs */
+ ljmpl $0, $realcseg
+
+realcseg:
+ /* we are in real mode now
+ * set up the real mode segment registers : DS, SS, ES
+ */
+ /* zero %eax */
+ xorl %eax, %eax
+
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
+#ifdef GRUB_MACHINE_PCBIOS
+ /* restore interrupts */
+ sti
+#endif
+
+ /* return on new stack! */
+ retl
+#endif
+ .code32
diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c
new file mode 100644
index 0000000..9293b16
--- /dev/null
+++ b/grub-core/kern/i386/tsc.c
@@ -0,0 +1,78 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module calibrates the TSC to real time.
+ *
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 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/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+#include <grub/i386/cpuid.h>
+
+/* This defines the value TSC had at the epoch (that is, when we calibrated it). */
+static grub_uint64_t tsc_boot_time;
+
+/* Calibrated TSC rate. (In ms per 2^32 ticks) */
+/* We assume that the tick is less than 1 ms and hence this value fits
+ in 32-bit. */
+grub_uint32_t grub_tsc_rate;
+
+static grub_uint64_t
+grub_tsc_get_time_ms (void)
+{
+ grub_uint64_t a = grub_get_tsc () - tsc_boot_time;
+ grub_uint64_t ah = a >> 32;
+ grub_uint64_t al = a & 0xffffffff;
+
+ return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate;
+}
+
+static int
+calibrate_tsc_hardcode (void)
+{
+ grub_tsc_rate = 5368;/* 800 MHz */
+ return 1;
+}
+
+void
+grub_tsc_init (void)
+{
+ if (!grub_cpu_is_tsc_supported ())
+ {
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_IEEE1275)
+ grub_install_get_time_ms (grub_rtc_get_time_ms);
+#else
+ grub_fatal ("no TSC found");
+#endif
+ return;
+ }
+
+ tsc_boot_time = grub_get_tsc ();
+
+#if defined (GRUB_MACHINE_XEN) || defined (GRUB_MACHINE_XEN_PVH)
+ (void) (grub_tsc_calibrate_from_xen () || calibrate_tsc_hardcode());
+#elif defined (GRUB_MACHINE_EFI)
+ (void) (grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_pit () || grub_tsc_calibrate_from_efi() || calibrate_tsc_hardcode());
+#elif defined (GRUB_MACHINE_COREBOOT)
+ (void) (grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_pit () || calibrate_tsc_hardcode());
+#else
+ (void) (grub_tsc_calibrate_from_pit () || calibrate_tsc_hardcode());
+#endif
+ grub_install_get_time_ms (grub_tsc_get_time_ms);
+}
diff --git a/grub-core/kern/i386/tsc_pit.c b/grub-core/kern/i386/tsc_pit.c
new file mode 100644
index 0000000..67990bf
--- /dev/null
+++ b/grub-core/kern/i386/tsc_pit.c
@@ -0,0 +1,84 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module uses the PIT to calibrate the TSC to
+ * real time.
+ *
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 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/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+#include <grub/i386/pit.h>
+#include <grub/cpu/io.h>
+
+static int
+grub_pit_wait (void)
+{
+ int ret = 0;
+
+ /* Disable timer2 gate and speaker. */
+ grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
+ & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
+ GRUB_PIT_SPEAKER_PORT);
+
+ /* Set tics. */
+ grub_outb (GRUB_PIT_CTRL_SELECT_2 | GRUB_PIT_CTRL_READLOAD_WORD,
+ GRUB_PIT_CTRL);
+ /* 0xffff ticks: 55ms. */
+ grub_outb (0xff, GRUB_PIT_COUNTER_2);
+ grub_outb (0xff, GRUB_PIT_COUNTER_2);
+
+ /* Enable timer2 gate, keep speaker disabled. */
+ grub_outb ((grub_inb (GRUB_PIT_SPEAKER_PORT) & ~ GRUB_PIT_SPK_DATA)
+ | GRUB_PIT_SPK_TMR2,
+ GRUB_PIT_SPEAKER_PORT);
+
+ if ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00) {
+ ret = 1;
+ /* Wait. */
+ while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
+ }
+
+ /* Disable timer2 gate and speaker. */
+ grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
+ & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
+ GRUB_PIT_SPEAKER_PORT);
+
+ return ret;
+}
+
+/* Calibrate the TSC based on the RTC. */
+int
+grub_tsc_calibrate_from_pit (void)
+{
+ /* First calibrate the TSC rate (relative, not absolute time). */
+ grub_uint64_t start_tsc, end_tsc;
+
+ start_tsc = grub_get_tsc ();
+ if (!grub_pit_wait ())
+ return 0;
+ end_tsc = grub_get_tsc ();
+
+ grub_tsc_rate = 0;
+ if (end_tsc > start_tsc)
+ grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - start_tsc, 0);
+ if (grub_tsc_rate == 0)
+ return 0;
+ return 1;
+}
diff --git a/grub-core/kern/i386/tsc_pmtimer.c b/grub-core/kern/i386/tsc_pmtimer.c
new file mode 100644
index 0000000..c9c3616
--- /dev/null
+++ b/grub-core/kern/i386/tsc_pmtimer.c
@@ -0,0 +1,88 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module uses the PIT to calibrate the TSC to
+ * real time.
+ *
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 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/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+#include <grub/i386/pmtimer.h>
+#include <grub/acpi.h>
+#include <grub/cpu/io.h>
+
+grub_uint64_t
+grub_pmtimer_wait_count_tsc (grub_port_t pmtimer,
+ grub_uint16_t num_pm_ticks)
+{
+ grub_uint32_t start;
+ grub_uint32_t last;
+ grub_uint32_t cur, end;
+ grub_uint64_t start_tsc;
+ grub_uint64_t end_tsc;
+ int num_iter = 0;
+
+ start = grub_inl (pmtimer) & 0xffffff;
+ last = start;
+ end = start + num_pm_ticks;
+ start_tsc = grub_get_tsc ();
+ while (1)
+ {
+ cur = grub_inl (pmtimer) & 0xffffff;
+ if (cur < last)
+ cur |= 0x1000000;
+ num_iter++;
+ if (cur >= end)
+ {
+ end_tsc = grub_get_tsc ();
+ return end_tsc - start_tsc;
+ }
+ /* Check for broken PM timer.
+ 50000000 TSCs is between 5 ms (10GHz) and 200 ms (250 MHz)
+ if after this time we still don't have 1 ms on pmtimer, then
+ pmtimer is broken.
+ */
+ if ((num_iter & 0xffffff) == 0 && grub_get_tsc () - start_tsc > 5000000) {
+ return 0;
+ }
+ }
+}
+
+int
+grub_tsc_calibrate_from_pmtimer (void)
+{
+ struct grub_acpi_fadt *fadt;
+ grub_port_t pmtimer;
+ grub_uint64_t tsc_diff;
+
+ fadt = grub_acpi_find_fadt ();
+ if (!fadt)
+ return 0;
+ pmtimer = fadt->pmtimer;
+ if (!pmtimer)
+ return 0;
+
+ /* It's 3.579545 MHz clock. Wait 1 ms. */
+ tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer, 3580);
+ if (tsc_diff == 0)
+ return 0;
+ grub_tsc_rate = grub_divmod64 ((1ULL << 32), tsc_diff, 0);
+ return 1;
+}
diff --git a/grub-core/kern/i386/xen/hypercall.S b/grub-core/kern/i386/xen/hypercall.S
new file mode 100644
index 0000000..09d75c3
--- /dev/null
+++ b/grub-core/kern/i386/xen/hypercall.S
@@ -0,0 +1,43 @@
+/* hypercall.S - wrappers for Xen hypercalls */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/>.
+ */
+
+#include <grub/symbol.h>
+#include <grub/xen.h>
+
+FUNCTION(grub_xen_hypercall)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ /* call number already in %eax. */
+ /* %edx -> %ebx*/
+ /* %ecx -> %ecx*/
+ movl %edx, %ebx
+ movl 8(%ebp), %edx
+ movl 12(%ebp), %esi
+ movl 16(%ebp), %edi
+ movl 20(%ebp), %ebp
+ int $0x82
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ ret
diff --git a/grub-core/kern/i386/xen/pvh.c b/grub-core/kern/i386/xen/pvh.c
new file mode 100644
index 0000000..91fbca8
--- /dev/null
+++ b/grub-core/kern/i386/xen/pvh.c
@@ -0,0 +1,369 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2018 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/>.
+ */
+
+#include <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/memory.h>
+#include <grub/mm.h>
+#include <grub/i386/cpuid.h>
+#include <grub/i386/io.h>
+#include <grub/xen.h>
+#include <xen/hvm/start_info.h>
+#include <grub/i386/linux.h>
+#include <grub/machine/kernel.h>
+#include <grub/machine/memory.h>
+#include <xen/hvm/params.h>
+#include <xen/memory.h>
+
+#define XEN_MEMORY_MAP_SIZE 128
+
+grub_uint64_t grub_rsdp_addr;
+
+static char hypercall_page[GRUB_XEN_PAGE_SIZE]
+ __attribute__ ((aligned (GRUB_XEN_PAGE_SIZE)));
+
+static grub_uint32_t xen_cpuid_base;
+static struct start_info grub_xen_start_page;
+static struct grub_e820_mmap_entry map[XEN_MEMORY_MAP_SIZE];
+static unsigned int nr_map_entries;
+
+static void
+grub_xen_cons_msg (const char *msg)
+{
+ const char *c;
+
+ for (c = msg; *c; c++)
+ grub_outb (*c, XEN_HVM_DEBUGCONS_IOPORT);
+}
+
+static void
+grub_xen_panic (const char *msg)
+{
+ grub_xen_cons_msg (msg);
+ grub_xen_cons_msg ("System halted!\n");
+
+ asm volatile ("cli");
+
+ while (1)
+ {
+ asm volatile ("hlt");
+ }
+}
+
+static void
+grub_xen_cpuid_base (void)
+{
+ grub_uint32_t base, eax, signature[3];
+
+ for (base = 0x40000000; base < 0x40010000; base += 0x100)
+ {
+ grub_cpuid (base, eax, signature[0], signature[1], signature[2]);
+ if (!grub_memcmp ("XenVMMXenVMM", signature, 12) && (eax - base) >= 2)
+ {
+ xen_cpuid_base = base;
+ return;
+ }
+ }
+
+ grub_xen_panic ("Found no Xen signature!\n");
+}
+
+static void
+grub_xen_setup_hypercall_page (void)
+{
+ grub_uint32_t msr, addr, eax, ebx, ecx, edx;
+
+ /* Get base address of Xen-specific MSRs. */
+ grub_cpuid (xen_cpuid_base + 2, eax, ebx, ecx, edx);
+ msr = ebx;
+ addr = (grub_uint32_t) (&hypercall_page);
+
+ /* Specify hypercall page address for Xen. */
+ asm volatile ("wrmsr" : : "c" (msr), "a" (addr), "d" (0) : "memory");
+}
+
+int
+grub_xen_hypercall (grub_uint32_t callno, grub_uint32_t a0,
+ grub_uint32_t a1, grub_uint32_t a2,
+ grub_uint32_t a3, grub_uint32_t a4,
+ grub_uint32_t a5 __attribute__ ((unused)))
+{
+ grub_uint32_t res;
+
+ asm volatile ("call *%[callno]"
+ : "=a" (res), "+b" (a0), "+c" (a1), "+d" (a2),
+ "+S" (a3), "+D" (a4)
+ : [callno] "a" (&hypercall_page[callno * 32])
+ : "memory");
+ return res;
+}
+
+static grub_uint32_t
+grub_xen_get_param (int idx)
+{
+ struct xen_hvm_param xhv;
+ int r;
+
+ xhv.domid = DOMID_SELF;
+ xhv.index = idx;
+ r = grub_xen_hypercall (__HYPERVISOR_hvm_op, HVMOP_get_param,
+ (grub_uint32_t) (&xhv), 0, 0, 0, 0);
+ if (r < 0)
+ grub_xen_panic ("Could not get parameter from Xen!\n");
+ return xhv.value;
+}
+
+static void *
+grub_xen_add_physmap (unsigned int space, void *addr)
+{
+ struct xen_add_to_physmap xatp;
+
+ xatp.domid = DOMID_SELF;
+ xatp.idx = 0;
+ xatp.space = space;
+ xatp.gpfn = (grub_addr_t) addr >> GRUB_XEN_LOG_PAGE_SIZE;
+ if (grub_xen_hypercall (__HYPERVISOR_memory_op, XENMEM_add_to_physmap,
+ (grub_uint32_t) (&xatp), 0, 0, 0, 0))
+ grub_xen_panic ("Memory_op hypercall failed!\n");
+ return addr;
+}
+
+static void
+grub_xen_sort_mmap (void)
+{
+ grub_uint64_t from, to;
+ unsigned int i;
+ struct grub_e820_mmap_entry tmp;
+
+ /* Align map entries to page boundaries. */
+ for (i = 0; i < nr_map_entries; i++)
+ {
+ from = map[i].addr;
+ to = from + map[i].len;
+ if (map[i].type == GRUB_MEMORY_AVAILABLE)
+ {
+ from = ALIGN_UP (from, GRUB_XEN_PAGE_SIZE);
+ to = ALIGN_DOWN (to, GRUB_XEN_PAGE_SIZE);
+ }
+ else
+ {
+ from = ALIGN_DOWN (from, GRUB_XEN_PAGE_SIZE);
+ to = ALIGN_UP (to, GRUB_XEN_PAGE_SIZE);
+ }
+ map[i].addr = from;
+ map[i].len = to - from;
+ }
+
+ again:
+ /* Sort entries by start address. */
+ for (i = 1; i < nr_map_entries; i++)
+ {
+ if (map[i].addr >= map[i - 1].addr)
+ continue;
+ tmp = map[i];
+ map[i] = map[i - 1];
+ map[i - 1] = tmp;
+ i = 0;
+ }
+
+ /* Detect overlapping areas. */
+ for (i = 1; i < nr_map_entries; i++)
+ {
+ if (map[i].addr >= map[i - 1].addr + map[i - 1].len)
+ continue;
+ tmp = map[i - 1];
+ map[i - 1].len = map[i].addr - map[i - 1].addr;
+ if (map[i].addr + map[i].len >= tmp.addr + tmp.len)
+ continue;
+ if (nr_map_entries < ARRAY_SIZE (map))
+ {
+ map[nr_map_entries].addr = map[i].addr + map[i].len;
+ map[nr_map_entries].len = tmp.addr + tmp.len - map[nr_map_entries].addr;
+ map[nr_map_entries].type = tmp.type;
+ nr_map_entries++;
+ goto again;
+ }
+ }
+
+ /* Merge adjacent entries. */
+ for (i = 1; i < nr_map_entries; i++)
+ {
+ if (map[i].type == map[i - 1].type &&
+ map[i].addr == map[i - 1].addr + map[i - 1].len)
+ {
+ map[i - 1].len += map[i].len;
+ map[i] = map[nr_map_entries - 1];
+ nr_map_entries--;
+ goto again;
+ }
+ }
+}
+
+static void
+grub_xen_get_mmap (void)
+{
+ struct xen_memory_map memmap;
+
+ memmap.nr_entries = ARRAY_SIZE (map);
+ set_xen_guest_handle (memmap.buffer, map);
+ if (grub_xen_hypercall (__HYPERVISOR_memory_op, XENMEM_memory_map,
+ (grub_uint32_t) (&memmap), 0, 0, 0, 0))
+ grub_xen_panic ("Could not get memory map from Xen!\n");
+ nr_map_entries = memmap.nr_entries;
+
+ grub_xen_sort_mmap ();
+}
+
+static void
+grub_xen_set_mmap (void)
+{
+ struct xen_foreign_memory_map memmap;
+
+ memmap.domid = DOMID_SELF;
+ memmap.map.nr_entries = nr_map_entries;
+ set_xen_guest_handle (memmap.map.buffer, map);
+ grub_xen_hypercall (__HYPERVISOR_memory_op, XENMEM_set_memory_map,
+ (grub_uint32_t) (&memmap), 0, 0, 0, 0);
+}
+
+static void
+grub_xen_mm_init_regions (void)
+{
+ grub_uint64_t modend, from, to;
+ unsigned int i;
+
+ modend = grub_modules_get_end ();
+
+ for (i = 0; i < nr_map_entries; i++)
+ {
+ if (map[i].type != GRUB_MEMORY_AVAILABLE)
+ continue;
+ from = map[i].addr;
+ to = from + map[i].len;
+ if (from < modend)
+ from = modend;
+ if (from >= to || from >= (1ULL << 32))
+ continue;
+ if (to > (1ULL << 32))
+ to = 1ULL << 32;
+ grub_mm_init_region ((void *) (grub_addr_t) from, to - from);
+ }
+}
+
+static grub_uint64_t
+grub_xen_find_page (grub_uint64_t start)
+{
+ unsigned int i, j;
+ grub_uint64_t last = start;
+
+ /*
+ * Try to find a e820 map hole below 4G.
+ * Relies on page-aligned entries (addr and len) and input (start).
+ */
+
+ for (i = 0; i < nr_map_entries; i++)
+ {
+ if (last > map[i].addr + map[i].len)
+ continue;
+ if (last < map[i].addr)
+ return last;
+ if ((map[i].addr >> 32) || ((map[i].addr + map[i].len) >> 32))
+ break;
+ last = map[i].addr + map[i].len;
+ }
+ if (i == nr_map_entries)
+ return last;
+
+ /* No hole found, use the highest RAM page below 4G and reserve it. */
+ if (nr_map_entries == ARRAY_SIZE (map))
+ grub_xen_panic ("Memory map size limit reached!\n");
+ for (i = 0, j = 0; i < nr_map_entries; i++)
+ {
+ if (map[i].type != GRUB_MEMORY_AVAILABLE)
+ continue;
+ if (map[i].addr >> 32)
+ break;
+ j = i;
+ if ((map[i].addr + map[i].len) >> 32)
+ break;
+ }
+ if (map[j].type != GRUB_MEMORY_AVAILABLE)
+ grub_xen_panic ("No free memory page found!\n");
+ if ((map[j].addr + map[j].len) >> 32)
+ last = (1ULL << 32) - GRUB_XEN_PAGE_SIZE;
+ else
+ last = map[j].addr + map[j].len - GRUB_XEN_PAGE_SIZE;
+ map[nr_map_entries].addr = last;
+ map[nr_map_entries].len = GRUB_XEN_PAGE_SIZE;
+ map[nr_map_entries].type = GRUB_MEMORY_RESERVED;
+ nr_map_entries++;
+ grub_xen_sort_mmap ();
+
+ return last;
+}
+
+void
+grub_xen_setup_pvh (void)
+{
+ grub_addr_t par;
+
+ grub_xen_cpuid_base ();
+ grub_xen_setup_hypercall_page ();
+ grub_xen_get_mmap ();
+
+ /* Setup Xen data. */
+ grub_xen_start_page_addr = &grub_xen_start_page;
+
+ par = grub_xen_get_param (HVM_PARAM_CONSOLE_PFN);
+ grub_xen_start_page_addr->console.domU.mfn = par;
+ grub_xen_xcons = (void *) (grub_addr_t) (par << GRUB_XEN_LOG_PAGE_SIZE);
+ par = grub_xen_get_param (HVM_PARAM_CONSOLE_EVTCHN);
+ grub_xen_start_page_addr->console.domU.evtchn = par;
+
+ par = grub_xen_get_param (HVM_PARAM_STORE_PFN);
+ grub_xen_start_page_addr->store_mfn = par;
+ grub_xen_xenstore = (void *) (grub_addr_t) (par << GRUB_XEN_LOG_PAGE_SIZE);
+ par = grub_xen_get_param (HVM_PARAM_STORE_EVTCHN);
+ grub_xen_start_page_addr->store_evtchn = par;
+
+ par = grub_xen_find_page (0);
+ grub_xen_grant_table = grub_xen_add_physmap (XENMAPSPACE_grant_table,
+ (void *) par);
+ par = grub_xen_find_page (par + GRUB_XEN_PAGE_SIZE);
+ grub_xen_shared_info = grub_xen_add_physmap (XENMAPSPACE_shared_info,
+ (void *) par);
+ grub_xen_set_mmap ();
+
+ grub_xen_mm_init_regions ();
+
+ grub_rsdp_addr = pvh_start_info->rsdp_paddr;
+}
+
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr_map_entries; i++)
+ {
+ if (map[i].len && hook (map[i].addr, map[i].len, map[i].type, hook_data))
+ break;
+ }
+
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/kern/i386/xen/startup.S b/grub-core/kern/i386/xen/startup.S
new file mode 100644
index 0000000..fbe8300
--- /dev/null
+++ b/grub-core/kern/i386/xen/startup.S
@@ -0,0 +1,38 @@
+/* startup.S - bootstrap GRUB itself */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/>.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+
+ .file "startup.S"
+ .text
+ .globl start, _start
+ .code32
+
+start:
+_start:
+ leal LOCAL(stack_end), %esp
+ movl %esi, EXT_C(grub_xen_start_page_addr)
+
+ call EXT_C(grub_main)
+ /* Doesn't return. */
+
+ .bss
+ .space (1 << 22)
+LOCAL(stack_end):
diff --git a/grub-core/kern/i386/xen/startup_pvh.S b/grub-core/kern/i386/xen/startup_pvh.S
new file mode 100644
index 0000000..363c318
--- /dev/null
+++ b/grub-core/kern/i386/xen/startup_pvh.S
@@ -0,0 +1,81 @@
+/* startup.S - bootstrap GRUB itself */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2018 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/>.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+#include <grub/machine/memory.h>
+
+ .file "startup_pvh.S"
+ .text
+ .globl start, _start
+ .code32
+
+start:
+_start:
+ cld
+ lgdt gdtdesc
+ ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $1f
+1:
+ movl $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %eax
+ mov %eax, %ds
+ mov %eax, %es
+ mov %eax, %fs
+ mov %eax, %gs
+ mov %eax, %ss
+ leal LOCAL(stack_end), %esp
+
+ /* Save address of start info structure. */
+ mov %ebx, pvh_start_info
+ call EXT_C(grub_main)
+ /* Doesn't return. */
+
+ .p2align 3
+gdt:
+ .word 0, 0
+ .byte 0, 0, 0, 0
+
+ /* -- code segment --
+ * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present
+ * type = 32bit code execute/read, DPL = 0
+ */
+ .word 0xFFFF, 0
+ .byte 0, 0x9A, 0xCF, 0
+
+ /* -- data segment --
+ * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
+ * type = 32 bit data read/write, DPL = 0
+ */
+ .word 0xFFFF, 0
+ .byte 0, 0x92, 0xCF, 0
+
+ .p2align 3
+/* this is the GDT descriptor */
+gdtdesc:
+ .word 0x17 /* limit */
+ .long gdt /* addr */
+
+ .p2align 2
+/* Saved pointer to start info structure. */
+ .globl pvh_start_info
+pvh_start_info:
+ .long 0
+
+ .bss
+ .space GRUB_MEMORY_MACHINE_PROT_STACK_SIZE
+LOCAL(stack_end):
diff --git a/grub-core/kern/i386/xen/tsc.c b/grub-core/kern/i386/xen/tsc.c
new file mode 100644
index 0000000..8792b30
--- /dev/null
+++ b/grub-core/kern/i386/xen/tsc.c
@@ -0,0 +1,40 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module uses the PIT to calibrate the TSC to
+ * real time.
+ *
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 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/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+#include <grub/xen.h>
+
+int
+grub_tsc_calibrate_from_xen (void)
+{
+ grub_uint64_t t;
+ t = grub_xen_shared_info->vcpu_info[0].time.tsc_to_system_mul;
+ if (grub_xen_shared_info->vcpu_info[0].time.tsc_shift > 0)
+ t <<= grub_xen_shared_info->vcpu_info[0].time.tsc_shift;
+ else
+ t >>= -grub_xen_shared_info->vcpu_info[0].time.tsc_shift;
+ grub_tsc_rate = grub_divmod64 (t, 1000000, 0);
+ return 1;
+}