aboutsummaryrefslogtreecommitdiffstats
path: root/grub-core/kern/i386/qemu
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/kern/i386/qemu')
-rw-r--r--grub-core/kern/i386/qemu/init.c147
-rw-r--r--grub-core/kern/i386/qemu/mmap.c100
-rw-r--r--grub-core/kern/i386/qemu/startup.S104
3 files changed, 351 insertions, 0 deletions
diff --git a/grub-core/kern/i386/qemu/init.c b/grub-core/kern/i386/qemu/init.c
new file mode 100644
index 0000000..054dfa8
--- /dev/null
+++ b/grub-core/kern/i386/qemu/init.c
@@ -0,0 +1,147 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/pci.h>
+#include <grub/machine/kernel.h>
+#include <grub/misc.h>
+#include <grub/vga.h>
+
+static struct {grub_uint8_t r, g, b, a; } colors[] =
+ {
+ // {R, G, B, A}
+ {0x00, 0x00, 0x00, 0xFF}, // 0 = black
+ {0x00, 0x00, 0xA8, 0xFF}, // 1 = blue
+ {0x00, 0xA8, 0x00, 0xFF}, // 2 = green
+ {0x00, 0xA8, 0xA8, 0xFF}, // 3 = cyan
+ {0xA8, 0x00, 0x00, 0xFF}, // 4 = red
+ {0xA8, 0x00, 0xA8, 0xFF}, // 5 = magenta
+ {0xA8, 0x54, 0x00, 0xFF}, // 6 = brown
+ {0xA8, 0xA8, 0xA8, 0xFF}, // 7 = light gray
+
+ {0x54, 0x54, 0x54, 0xFF}, // 8 = dark gray
+ {0x54, 0x54, 0xFE, 0xFF}, // 9 = bright blue
+ {0x54, 0xFE, 0x54, 0xFF}, // 10 = bright green
+ {0x54, 0xFE, 0xFE, 0xFF}, // 11 = bright cyan
+ {0xFE, 0x54, 0x54, 0xFF}, // 12 = bright red
+ {0xFE, 0x54, 0xFE, 0xFF}, // 13 = bright magenta
+ {0xFE, 0xFE, 0x54, 0xFF}, // 14 = yellow
+ {0xFE, 0xFE, 0xFE, 0xFF} // 15 = white
+ };
+
+#include <ascii.h>
+
+static void
+load_font (void)
+{
+ unsigned i;
+
+ grub_vga_gr_write (0 << 2, GRUB_VGA_GR_GR6);
+
+ grub_vga_sr_write (GRUB_VGA_SR_MEMORY_MODE_NORMAL, GRUB_VGA_SR_MEMORY_MODE);
+ grub_vga_sr_write (1 << GRUB_VGA_TEXT_FONT_PLANE,
+ GRUB_VGA_SR_MAP_MASK_REGISTER);
+
+ grub_vga_gr_write (0, GRUB_VGA_GR_DATA_ROTATE);
+ grub_vga_gr_write (0, GRUB_VGA_GR_MODE);
+ grub_vga_gr_write (0xff, GRUB_VGA_GR_BITMASK);
+
+ for (i = 0; i < 128; i++)
+ grub_memcpy ((void *) (0xa0000 + 32 * i), ascii_bitmaps + 16 * i, 16);
+}
+
+static void
+load_palette (void)
+{
+ unsigned i;
+ for (i = 0; i < 16; i++)
+ grub_vga_write_arx (i, i);
+
+ for (i = 0; i < ARRAY_SIZE (colors); i++)
+ grub_vga_palette_write (i, colors[i].r, colors[i].g, colors[i].b);
+}
+
+void
+grub_qemu_init_cirrus (void)
+{
+ auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid);
+ int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused)))
+ {
+ grub_pci_address_t addr;
+ grub_uint32_t class;
+
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
+ class = grub_pci_read (addr);
+
+ if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA)
+ return 0;
+
+ /* FIXME: chooose addresses dynamically. */
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
+ grub_pci_write (addr, 0xf0000000 | GRUB_PCI_ADDR_MEM_PREFETCH
+ | GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_32);
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1);
+ grub_pci_write (addr, 0xf2000000
+ | GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_32);
+
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
+ grub_pci_write (addr, GRUB_PCI_COMMAND_MEM_ENABLED
+ | GRUB_PCI_COMMAND_IO_ENABLED);
+
+ return 1;
+ }
+
+ grub_pci_iterate (find_card);
+
+ grub_outb (GRUB_VGA_IO_MISC_COLOR, GRUB_VGA_IO_MISC_WRITE);
+
+ load_font ();
+
+ grub_vga_gr_write (GRUB_VGA_GR_GR6_MMAP_CGA, GRUB_VGA_GR_GR6);
+ grub_vga_gr_write (GRUB_VGA_GR_MODE_ODD_EVEN, GRUB_VGA_GR_MODE);
+
+ grub_vga_sr_write (GRUB_VGA_SR_MEMORY_MODE_NORMAL, GRUB_VGA_SR_MEMORY_MODE);
+
+ grub_vga_sr_write ((1 << GRUB_VGA_TEXT_TEXT_PLANE)
+ | (1 << GRUB_VGA_TEXT_ATTR_PLANE),
+ GRUB_VGA_SR_MAP_MASK_REGISTER);
+
+ grub_vga_cr_write (15, GRUB_VGA_CR_CELL_HEIGHT);
+ grub_vga_cr_write (79, GRUB_VGA_CR_HORIZ_END);
+ grub_vga_cr_write (40, GRUB_VGA_CR_PITCH);
+
+ int vert = 25 * 16;
+ grub_vga_cr_write (vert & 0xff, GRUB_VGA_CR_VDISPLAY_END);
+ grub_vga_cr_write (((vert >> GRUB_VGA_CR_OVERFLOW_HEIGHT1_SHIFT)
+ & GRUB_VGA_CR_OVERFLOW_HEIGHT1_MASK)
+ | ((vert >> GRUB_VGA_CR_OVERFLOW_HEIGHT2_SHIFT)
+ & GRUB_VGA_CR_OVERFLOW_HEIGHT2_MASK),
+ GRUB_VGA_CR_OVERFLOW);
+
+ load_palette ();
+
+ grub_vga_write_arx (GRUB_VGA_ARX_MODE_TEXT, GRUB_VGA_ARX_MODE);
+ grub_vga_write_arx (0, GRUB_VGA_ARX_COLOR_SELECT);
+
+ grub_vga_sr_write (GRUB_VGA_SR_CLOCKING_MODE_8_DOT_CLOCK,
+ GRUB_VGA_SR_CLOCKING_MODE);
+
+ grub_vga_cr_write (14, GRUB_VGA_CR_CURSOR_START);
+ grub_vga_cr_write (15, GRUB_VGA_CR_CURSOR_END);
+
+ grub_outb (0x20, 0x3c0);
+}
diff --git a/grub-core/kern/i386/qemu/mmap.c b/grub-core/kern/i386/qemu/mmap.c
new file mode 100644
index 0000000..208f36b
--- /dev/null
+++ b/grub-core/kern/i386/qemu/mmap.c
@@ -0,0 +1,100 @@
+/*
+ * 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 ()
+{
+ mem_size = ((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH)) << 24
+ | ((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW)) << 16;
+ if (mem_size > 0)
+ {
+ /* Don't ask... */
+ mem_size += (16 * 1024 * 1024);
+ }
+ else
+ {
+ mem_size
+ = ((((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE2_HIGH)) << 18)
+ | ((grub_uint64_t) (grub_cmos_read (QEMU_CMOS_MEMSIZE2_LOW)) << 10))
+ + 1024 * 1024;
+ }
+
+ above_4g = (((grub_uint64_t) grub_cmos_read (0x5b)) << 16)
+ | (((grub_uint64_t) grub_cmos_read (0x5c)) << 24)
+ | (((grub_uint64_t) grub_cmos_read (0x5d)) << 32);
+}
+
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook)
+{
+ if (hook (0x0,
+ (grub_addr_t) _start,
+ GRUB_MEMORY_AVAILABLE))
+ return 1;
+
+ if (hook ((grub_addr_t) _end,
+ 0xa0000 - (grub_addr_t) _end,
+ GRUB_MEMORY_AVAILABLE))
+ return 1;
+
+ if (hook (GRUB_MEMORY_MACHINE_UPPER,
+ 0x100000 - GRUB_MEMORY_MACHINE_UPPER,
+ GRUB_MEMORY_RESERVED))
+ return 1;
+
+ /* Everything else is free. */
+ if (hook (0x100000,
+ min (mem_size, (grub_uint32_t) -GRUB_BOOT_MACHINE_SIZE) - 0x100000,
+ GRUB_MEMORY_AVAILABLE))
+ 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))
+ return 1;
+
+ if (above_4g != 0 && hook (0x100000000ULL, above_4g,
+ GRUB_MEMORY_AVAILABLE))
+ 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..7834d1d
--- /dev/null
+++ b/grub-core/kern/i386/qemu/startup.S
@@ -0,0 +1,104 @@
+/*
+ * 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/i386/pc/memory.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/kernel.h>
+
+ .text
+ .code32
+ .globl _start
+_start:
+ jmp codestart
+
+ . = _start + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR
+VARIABLE(grub_core_entry_addr)
+ .long 0
+VARIABLE(grub_kernel_image_size)
+ .long 0
+VARIABLE(grub_prefix)
+ /* to be filled by grub-mkimage */
+
+ /*
+ * Leave some breathing room for the prefix.
+ */
+
+ . = _start + GRUB_KERNEL_MACHINE_PREFIX_END
+
+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
+
+ /* ... which allows us to access `grub_kernel_image_size'
+ before relocation. */
+ movl (grub_kernel_image_size - _start)(%esi), %ecx
+
+
+ movl $_start, %edi
+ cld
+ rep
+ movsb
+ ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $1f
+1:
+
+#ifdef APPLE_CC
+ /* clean out the bss */
+ bss_start_abs = ABS (bss_start)
+ bss_end_abs = ABS (bss_end)
+
+ movl bss_start_abs, %edi
+
+ /* compute the bss length */
+ movl bss_end_abs, %ecx
+ subl %edi, %ecx
+#else
+ /* clean out the bss */
+ movl $BSS_START_SYMBOL, %edi
+
+ /* compute the bss length */
+ movl $END_SYMBOL, %ecx
+ subl %edi, %ecx
+#endif
+
+ /* 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
+
+#include "../realmode.S"